BTObex Library

I’ve released the BTObex library (I’m playing around with using bitbucket for hosting the code) I wrote a few months ago which is a Win32 bluetooth library that allows for file transfers with devices that support the Bluetooth File Transfer Profile. This library uses the MS Bluetooth stack (included w/ Win XP SP2 and later).

For those wondering what OBEX is and what Bluetooth has to do with it: Bluetooth devices support a set of profiles, one of which is the File Transfer Profile. However, the FTP itself doesn’t really take care of anything much, once the connection is established, actual file transfers are handled by the OBEX protocol.

Bluetooth FTP stack

OBEX was originally designed for transfers across infrared devices and is not handled by the Bluetooth SIG, its specs are controlled by the IrDA. Now, aside from being a useless bit of trivia, this is important because while the Bluetooth SIG publishes a ton of documentation, the IrDA does not. The documentation on the specs for OBEX requires signing up for IrDA membership and paying some hefty membership fees. That said I was able to get my hands on a copy of the OBEX documentation here. How long that remains up and the legality of me reading it is up in the air. Charging for documentation is a shitty practice by the IrDA and I can only hope that the Bluetooth SIG ditches OBEX for something better in the future.

There’s little-to-no documentation for the library, so I’m going to use this blog post to provide some examples.

Link with necessary libraries

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "irprops.lib")

Include header file

#include "BTOBEX.h"

The entire library simply consists of a bunch of header files. BTOBEX.h will include everything else.

Query all Bluetooth devices

std::vector<BTSock::Device*> btDevices;
BTSock::Session* btSession =
new BTSock::Session();
btSession->DeviceQueryObject()->PerformQuery(btDevices);
delete btSession;

The vector btDevices will contain an entry for each device paired with the system. Look at BTSockDevice.h to see the structure of the BTSock::Device class.

Make a connection

BTOBEX::Session* btObexSession = new BTOBEX::Session();
bool connOk = btObexSession->Connect(devAddress, port, 8192);

devAddress is the deviceAddress member of a BTSock::Device object.
port is the port number for a given profile, for the file transfer profile it’s 5. If you can’t connect on the port, it likely means that the profile is not support by the device.

Set the current directory on the device

bool setPathOk = btObexSession->SetPathForward(L"my_picture");

OBEX only allows you to move forward into a subdirectory (SetPathForward) or jump back to a parent directory (SetPathForward).

Get a directory listing

OBEX::NakedVector<OBEX::byte> xmlBytes;
btObexSession->GetFolderListing(xmlBytes);

The bytes are UTF-8 bytes that form a XML document (an XML parser is not part of the library). The XML doc will have folder and/or file elements, each with a required name attribute. Directory listings are one of the dumbest aspects of the OBEX protocol; whereas everything else is binary and well-defined, directory listings are verbose and text-based (remember, this is a low bandwidth connection) and have no required attribute aside from name. Other attributes (e.g. size) may be present, but they’re optional, meaning, in general, you’ll likely avoid them in order to develop for the lowest common denominator.

Get a file from the device

bool getOk = btObexSession->GetFile(L"remote.jpg", L"local.jpg", new BTOBEX::Progress());

The last parameter is optional, you can pass a BTOBEX::Progress object if you wish to poll the progress of the transfer from another thread.

Put a file on the device

bool putOk = btObexSession->PutFile(L"remote.jpg", L"local.jpg", new BTOBEX::Progress());

The last parameter is optional, you can pass a BTOBEX::Progress object if you wish to poll the progress of the transfer from another thread.

Disconnect and clean up

btObexSession->Disconnect();
delete btObexSession;

Have fun! The code is released under the BSD license. Any comments or bug reports are greatly appreciated.

Edit (11/22/2020): Update link to point to GitHub repo.

23 Comments

  1. guy

    I see an empty repository, but this library sounds very useful. Any plans to reupload?

  2. aautar

    The repo isn’t empty, are you having issues cloning it?
    I had no issues cloning it or downloading a zip with the source from bitbucket.

  3. guy

    Today it worked! Thanks for a great lib!

  4. Makx

    Thank you for the Post! This really clarified some things for me.
    I am currently fighting with Bluetooth on windows – the documentation is really meager and confusing.

    Maybe you can point me to another thing:
    I am to write a Bluetooth Server application (C++/Windows7) that mobile devices can use to push files onto the Server.
    So I have to figure out how to make it connectable with little or no authentication (can’t use the Windows pairing wizard) and accept incoming OBEX commands.

    There is a Windows Documentation on how to replace the standard OBEX app on windows with an own application (in the registry), but that would still leave me with the Windows Pairing Server/Wizard.

    Any ideas on how to get by that would be very welcome!

  5. Avishkar Autar

    Makx,

    I actually looked into something similar a while back, but didn’t come up with anything. Windows seems to require all pairing/authentication done via. the pairing wizard.

  6. Makx

    Thank you for your reply!

    I have tried several ways to get around this or mimic other services, but I could not get it to work.
    So I’m giving up on this now. Took too much time already.

    Thank you for your code and your clear words. I wish my requests to Microsoft support would have been so clearly and quickly answered. 😉
    Well – I know a lot more about Bluetooth protocol(s) now.

    Have a nice day and keep up the good work!

  7. […] the most elegant way to query it. I haven’t written any documentation so, as I did with the bluetooth stuff, I’ll post a quick-and-dirty tutorial […]

  8. Great job, Avishkar! I have been searching long for such kind of software. I have included into my MFC program, and did some minor fixes here and there. What I need is even simpler, I need the OBEXObjectPushServiceClass_UUID service instead of OBEXFileTransferServiceClass_UUID. I don’t need access to the phone’s file system, only want to send it a .jar file for installation. Where do I have to hook in to achieve that? Of course I’ll send you a copy of my modifications/extensions.

    Regards,
    Hans

  9. Avishkar Autar

    The port in the OBEX::Session::Connect() call determines the service class.
    I don’t know what the port for OBEX Object Push is and I can’t look it up as I’m on a Windows Server machine which doesn’t allow installation of BT drivers.

    But to find the port, do a query for all devices/profiles, shown above under “Query all Bluetooth devices”

    For your bluetooth device (the BTSock::Device object), go through the supported profiles (BTSock::Device::supportedProfiles), the OBEX Object Push profile should be one of them. BTSock::DeviceProfile::port will give you the port number for the connect call.

  10. I made some changes to make everything UUID based instead of port based. From my application I write:

    // if (m_btObexSession->Connect(devAddress, OBEXFileTransferServiceClass_UUID))
    if (m_btObexSession->Connect(devAddress, OBEXObjectPushServiceClass_UUID))
    .
    .

    Connection is not the problem, I added this code:

    // added this overwrite, HJU
    bool Connect(Socket* sock, const std::wstring& devAddress, GUID service)
    {
    BTH_ADDR btAddr = 0;
    BTAddressFromString(devAddress, btAddr);
    SOCKADDR_BTH sockAddr = { 0 };
    sockAddr.addressFamily = AF_BTH;
    sockAddr.btAddr = btAddr;
    sockAddr.serviceClassId = service;
    sockAddr.port = (ULONG) BT_PORT_ANY;
    int ret = ::connect(sock->btSock, (sockaddr*) &sockAddr, sizeof(SOCKADDR_BTH));
    return (ret == 0);
    }

    Still all ok here, even

    OBEX::Packet* connectPckt = OBEX::BluetoothFtpPacketMaker::MakeConnectPacket(maxPacketSize);

    doesn’t complain although I don’t wanna make FTP. But after I called

    ret = btSession->Recv(btSock, recvBuf, maxPacketSize);

    I see that opcode 0xc3 in recvBuf which means OBEX_FORBIDDEN

    In my opinion I don’t need OBEX::BluetoothFtpPacketMaker, I need something else.
    There is no problem with the FTP profile, my phone says ” wants to access your data, will you allow?”, I click ‘yes’ and then have to confirm to accept the data and the file is tranferred and installed. But sending it from the windows desktop I don’t get that access question, just the receive confirmation.

    Hans

  11. From OBEX::ResponsePacketParser::GetHeader()

    NakedVector& bytes = *packet->ToBytes();

    I really don’t understand this construct, but it causes memory leaks!

  12. I forgot this to append:

    Dumping objects ->
    {30553} normal block at 0x03719FA8, 4 bytes long.
    Data: D0 DA 71 03
    {30552} normal block at 0x0371DA10, 64 bytes long.
    Data: CB 00 00 00 63 CD CD CD CD CD CD CD CD CD CD CD
    {30551} normal block at 0x0371D9C8, 12 bytes long.
    Data: 10 DA 71 03 05 00 00 00 40 00 00 00
    {30550} normal block at 0x0371DB18, 64 bytes long.
    Data: 81 00 08 CB 00 00 00 63 CD CD CD CD CD CD CD CD
    {30549} normal block at 0x0371DAD0, 12 bytes long.
    Data: 18 DB 71 03 08 00 00 00 40 00 00 00
    {30545} normal block at 0x0371DA90, 4 bytes long.
    Data: 88 DC 71 03
    {30542} normal block at 0x0371DCD0, 64 bytes long.
    Data: 81 00 08 CB 00 00 00 63 CD CD CD CD CD CD CD CD
    {30541} normal block at 0x0371DC88, 12 bytes long.
    Data: D0 DC 71 03 08 00 00 00 40 00 00 00
    {28566} normal block at 0x0032FAF8, 8 bytes long.
    Data: E1 BE 00 00 E1 BE 00 00
    {28565} normal block at 0x0371DC08, 64 bytes long.
    Data: 00 00 00 63 CD CD CD CD CD CD CD CD CD CD CD CD
    {28564} normal block at 0x0032FAA0, 24 bytes long.
    Data: CB 00 00 00 05 00 00 00 08 DC 71 03 04 00 00 00
    Object dump complete.

  13. I finally got the OPP service working. On my way searching for a solution I found 2 bugs (unverified NULL pointers). When you send me your mail address I’ll send you a copy of my changes and extensions. There are 2 issues left:

    1. A memory leak of 8 bytes:
    Dumping objects ->
    {28631} normal block at 0x00B55468, 8 bytes long.
    Data: 00 04 00 00 E1 BE 00 00
    Object dump complete.

    2.
    OBEX::Header* length = new Header(HeaderFieldCode::OBEX_HEADER_LENGTH, size); // added, HJU

    shows a wrong object size on the OPP target. (448 KB instead of 47 KB)

  14. Avishkar Autar

    awesome! I’ll incorporate the changes/additions when I get a chance.

    You can send code to aautar@fragmentspace.com

  15. Ankur Sharma

    Hi Autar,

    I am not able to download this. Could you please send the zipped file to my id ankursharma012@gmail.com. I have been trying cloning it from past 2 days but failed. Please do the needful. Need this urgently.

    Thanks
    Ankur

  16. Avishkar Autar

    You can get a zip directly from bitbucket:

    https://bitbucket.org/aautar/btobex-library/get/3bde1cbfe3f1.zip

    (top-right, get source)

  17. Autoregister

    Hi, I’m reading this code these days, and My requirement is same to Han’s. MSDN says OPP is supported on win7. But I can’t find any exposed APIs actually. There are some problems when I try to modify the code. Could you please share Han’s changes with me? thx~ autoregister@163.com

  18. Avishkar Autar

    I don’t know about the changes Hans made, they weren’t sent to me.
    As-is the library will only support OBEX file transfer, not Object Push.

  19. easterDDPhone

    Hi Autar,
    The OBEX library has only “.h” files. Could you please offer me an example how to use them?
    In another words,I want to use these “.h” to send a file,what should i do in my program after including these “.h”.
    my email:lao284782880@126.com
    thanks a lot.

  20. easterDDPhone

    Hi Autra?
    when I connect the target Bluetooth device with “btObexSession->Connect(devAddress, port, 8192)”, if i set port=5,it fails,but if i set port=1,it successes;
    As you mentioned “ort is the port number for a given profile, for the file transfer profile it’s 5. If you can’t connect on the port, it likely means that the profile is not support by the device”.
    But if I tranfer file to bluetooth device by windows bluetooth instead of code,it works normally.
    In another words,the profile support by the device. I don’t know what is wrong,do i leak anything?
    expect you reply,thanks!

  21. easterDDPhone

    Hi Autra?
    when I connect the target Bluetooth device with “btObexSession->Connect(devAddress, port, 8192)”, if i set port=5,it fails,but if i set port=1,it successes;
    As you mentioned “ort is the port number for a given profile, for the file transfer profile it’s 5. If you can’t connect on the port, it likely means that the profile is not support by the device”.
    But if I tranfer file to bluetooth device by windows bluetooth instead of code,it works normally.
    In another words,the profile support by the device. I don’t know what is wrong,do i leak anything?
    expect you reply,thanks!

  22. easterDDPhone

    is “fileBrowsingUUID” fixed? what does it represent?

  23. 64bit

    Hello!

    How can I use this library ?
    I would like to send files to Android phones via OBEX.

    I’ve made it that here comes a 1.

    bool connOk = btObexSession->Connect(btDevices[0]->deviceAddress, OBEXObjectPushServiceClass_UUID, dev_p->port);

    std::cout << connOk << "\n";

    (Converted according to tips on this page.)

    But if I want to transfer files, the file size is always -1.

    And it doesn't start file transfer.

    The send notification also comes only after turning on Bluetooth again on the phone.

    There are also memory errors.

    How can I fix the problems?

    I work with Microsoft Visual Studio Community 2019.

    Thank you in advance.