androidc++bluetoothwinsock2obex

Error transfering files to Android using Windows C++ Bluetooth OBEX socket


OBEX is probably the most commonly used technique to transfer files over devices that support Bluetooth. On the contrary , with being the most common , it is not very well documented how this thing actually works.

I have not much experience in OBEX. My objective is to design an OBEX client server on my laptop which should send files to my android device with popup like this.

I have chosen C++ as the language to program the server from scratch on Windows. The UUID for this action which I am using is this.

00001105-0000-1000-8000-00805F9B34FB

and I have initialised the OBEX client like this.

    GUID OBEX_GUID;

    UuidFromString((unsigned char*)"00001105-0000-1000-8000-00805F9B34FB",(UUID*)&OBEX_GUID);
    
    SOCKET soc,acpt;
    SOCKADDR_BTH BluetoothAddress;
    
    BluetoothAddress.addressFamily = AF_BTH;
    BluetoothAddress.port = BT_PORT_ANY;
    str2ba((char*)"BC:41:01:11:BC:2F",&BluetoothAddress.btAddr);
    BluetoothAddress.serviceClassId = OBEX_GUID;
     //OBEXObjectPushServiceClass_UUID;
    
    soc = socket(AF_BTH , SOCK_STREAM , BTHPROTO_RFCOMM);
    
    if(soc>0){
        printf("Socket initialisation success\n");
    }
    
    stat = connect(soc,(sockaddr*)&BluetoothAddress,sizeof(BluetoothAddress));
    printf("%s\n\n",(stat==0) ? "CONNECTED to the remote device!" : "Remote device is unavailable." );
    

This connect process is successful yet , and without any error it starts communication with my Android device addressed BC:41:01:11:BC:2F. The status of the socket connect() function returns zero (success as well).

Now, as per OBEX 1.4 pdf , I need to start the session after the connection is estabilished successfully. So in the Page 38 of the PDF , the starting session of connection is well described and I tried to imitate the syntax of the connecting package like this

char connect_req[] = {
        0x80 , 0x00 , 0x11 , 0x10 , 0x00 , 0x20 , 0x00 , 0xc0  , 0x00 , 0x00 , 0x00 , 0x01 , 0xc3       ,   0x00 , 0x00 , 0xf4 , 0x83        
    //  CNCT | 2B Length   | Vers | Flag | Max Pack 8K | Count | 4 byte file count         | Len Header |   Total length of hex
};

Upon sending this connect package to my Android, it returns successfully with the value of 0xA0. Which means that a session has finally been started.

After the session is started , I need to send a dummy file which requires to be requested as a PUT method which is defined in the page 40 of the PDF. tried to do the same imitation and ended up with a package like this.

unsigned char putfile_req[] = {
        0x82 , 0x00 , 0x21 , 0x01    , 0x00 , 0x17 ,   0x00,0x41   ,  0x00,0x42  ,  0x00,0x43  , 0x00,0x44  , 0x00,0x45 , 0x00,0x2c ,  0x00,0x74  ,  0x00,0x78 ,  0x00,0x74  ,  0xC3 ,  0x00 , 0x00 , 0x00 , 0x01 ,  0x49  , 0x00 , 0x01 ,  0x74
//      PUT  |  2b Len     | HI Name |  NameLen    |       A              B             C            D             E           .           T             X            T      |  Len  |              1  Byte       |  end   |     1 Byte  |  
};
    

Upon sending this PUT request with the filename of, ABCDE.TXT (1 Byte), the response from my android somehow returns unsuccessful with the value of Zero (0)

The problem is, till the connect session state every request and response worked perfectly fine but whenever I am sending a PUT request with a file name, it is received by the Android but for some unknown reasons the Android can not proces it and returns zero.

I have heard some people saying that Android does not support OBEX but had that been the actual factor , the success (A0) status would not have returned while sending the connect package in the beginning.

Here is the full code if matters...

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>

#include <winsock2.h>
#include <windows.h>

#include <ws2bth.h>
#include <bthsdpdef.h>
#include <bluetoothapis.h>
#include <ws2bth.h>

GUID OBEX_GUID;



int str2ba(const char *straddr, BTH_ADDR *btaddr)
{
    int i;
    unsigned int aaddr[6];
    BTH_ADDR tmpaddr = 0;

    if (sscanf(straddr, "%02x:%02x:%02x:%02x:%02x:%02x",
                    &aaddr[0], &aaddr[1], &aaddr[2],
                    &aaddr[3], &aaddr[4], &aaddr[5]) != 6)
        return 1;
    *btaddr = 0;
    for (i = 0; i < 6; i++) {
        tmpaddr = (BTH_ADDR) (aaddr[i] & 0xff);
        *btaddr = ((*btaddr) << 8) + tmpaddr;
    }
    return 0;
}



int main(){
    
    unsigned char response[10000]={0};
    
    UuidFromString((unsigned char*)"00001105-0000-1000-8000-00805F9B34FB",(UUID*)&OBEX_GUID);
    
    WSADATA ws;
    WSAStartup(MAKEWORD(2,2),&ws);
    
    int stat;
    SOCKET soc,acpt;
    SOCKADDR_BTH BluetoothAddress;
    
    BluetoothAddress.addressFamily = AF_BTH;
    BluetoothAddress.port = BT_PORT_ANY;
    str2ba((char*)"BC:41:01:11:BC:2F",&BluetoothAddress.btAddr);
    BluetoothAddress.serviceClassId = OBEX_GUID;
     OBEXObjectPushServiceClass_UUID;
    
    soc = socket(AF_BTH , SOCK_STREAM , BTHPROTO_RFCOMM);
    
    if(soc>0){
        printf("Socket initialisation success\n");
    }
    
    stat = connect(soc,(sockaddr*)&BluetoothAddress,sizeof(BluetoothAddress));
    printf("%s\n\n",(stat==0) ? "CONNECTED to the remote device!" : "Remote device is unavailable." );
    
    
    
    
    char connect_req[] = {
        0x80 , 0x00 , 0x11 , 0x10 , 0x00 , 0x20 , 0x00 , 0xc0  , 0x00 , 0x00 , 0x00 , 0x01 , 0xc3       ,   0x00 , 0x00 , 0xf4 , 0x83        
    //  CNCT | 2B Length   | Vers | Flag | Max Pack 8K | Count | 4 byte file count         | Len Header |   Total length of hex
    };
    
    
    
    unsigned char putfile_req[] = {
        0x82 , 0x00 , 0x21 , 0x01    , 0x00 , 0x17 ,   0x00,0x41   ,  0x00,0x42  ,  0x00,0x43  , 0x00,0x44  , 0x00,0x45 , 0x00,0x2c ,  0x00,0x74  ,  0x00,0x78 ,  0x00,0x74  ,  0xC3 ,  0x00 , 0x00 , 0x00 , 0x01 ,  0x49  , 0x00 , 0x01 ,  0x74
//      PUT  |  2b Len     | HI Name |  NameLen    |       A              B             C            D             E           .           T             X            T      |  Len  |              1  Byte       |  end   |     1 Byte  |  
    };
    
    
    printf("PUT packet Length: %d\n\n",sizeof(putfile_req)/sizeof(unsigned char));
    

    send(soc,(const char*)connect_req,sizeof(connect_req)/sizeof(connect_req[0]),0);
    int Recvd = recv(soc,(char*)response,sizeof(response),0);
    
    printf("OBEX CONNECT status: %X\n",response[0]);
    if(response[0]==0xA0){
        printf(" SUCCESS\n");
    }
    
    memset(response,0,sizeof(response));
    
    send(soc,(char*)putfile_req,sizeof(putfile_req)/sizeof(putfile_req[0]),0);
    Recvd = recv(soc,(char*)response,sizeof(response),0);
    
    printf("PUT Request status: %X\n",response[0]);
    
    if(response[0]==0x00){
        printf("Something went wrong!\n");
    }
    
    
}

And the output looks like, enter image description here Even though the connect session is successful with the return value of 0xA0, the socket closes with an error code of zero as the response of PUT request. Hence the popup dialogue at my Android side is not supposed to appear.

Now ,all I want is to send a file from the Winsock2 OBEX client written from scratch , to my Android where there should appear a popup in my Android device asking for the user to accept or decline the incoming file or request. upon acceptance , the file transfer should begin.

So this somehow seems to be my fault , which I can not diagnose. That is why I am here to ask for some kind advices and helps from those who are well experienced in this field.

Thanks and Regards.


Solution

  • I have a C programmed OBEX client that sends the following commands to Android successfully. Name = hello.txt. Data = Hello. Chunk size = 400. Data size = 5. The data size must be sent in the 0xC3 4-byte item, your code seems to have a value of 1.

    unsigned char connect[7] = {0x80,0x00,0x07,0x10,0x00,0x01,0x90};
    unsigned char send[39] = {0x82,0x00,0x27,
    0x01,0x00,0x17,0,'h',0,'e',0,'l',0,'l',0,'o',0,'.',0,'t',0,'x',0,'t',0,0,
    0xC3,0,0,0,5,
    0x49,0,8,'H','e','l','l','o'};
    unsigned char disconnect[3] = {0x81,0x00,0x03};   
    

    The sizes that must be set are as follows. Each command: bytes [1] = hi byte and [2] = lo bytes are the size of the entire packet. So send is 39 bytes = 0x0027. A put command (0x82 or 0x02) can contain a number of items, each has a header identifier 01, C3, 49 in the example. The two hi bits of the identifier specify the size of the item. 10xxxxxx is 1 byte. 11xxxxxx (C3) is 4 byte. 00xxxxx and 01xxxxxx (01, 49) are followed by two size bytes. The 01 item is 23 bytes from the initial 01 to the final 0, so is 0x0017. It is the size of the item not the file. C3 item = file size.

    This is my file send routine. The write_node and read_node functions send and receive the Bluetooth packets. You will need your own implementation.

    int sendfileobex(int node,char *filename)
      {
      int n,k,fn,flen,nlen,ndat,ntogo,nblock,len,err;
      unsigned char inbuf[64],send[512];
      static unsigned char connect[7] = {0x80,0x00,0x07,0x10,0x00,0x01,0x90};
      static unsigned char disconnect[3] = {0x81,0x00,0x03};   
      char *fname;
      FILE *stream;
    
      fn = 0;  // strip path 
      n = 0;
      while(filename[n] > 32 && n < 1022)
        {   
        if(filename[n] == '/' || filename[n] == '\\')
          fn = n+1;  // start of file name
        ++n;
        }
        
      fname = filename+fn;
      
      printf("Sending file %s\n",filename);
    
      stream = fopen(filename,"r");
      if(stream == NULL)
        {
        printf("File open error\n");
        return(0);
        }
      
      fseek(stream,0,SEEK_END);
      flen = ftell(stream);  // file length
      fseek(stream,0,SEEK_SET);  
        
      ntogo = flen; 
      nlen = strlen(fname);
    
      nblock = 400;
      connect[5] = (nblock >> 8) & 0xFF;
      connect[6] = nblock & 0xFF;
    
      // OBEX connect
      write_node(node,connect,7);  
      inbuf[0] = 0;
      // wait for Success reply 0x0A
      len = read_node_endchar(node,inbuf,64,PACKET_ENDCHAR,EXIT_TIMEOUT,5000);
      if(len == 0 || inbuf[0] != 0xA0)
        {
        printf("OBEX Connect failed\n");
        fclose(stream);
        return(0);
        }
      else if((inbuf[1] << 8) + inbuf[2] >= 7)
        {
        n = (inbuf[5] << 8) + inbuf[6];
        if(n < nblock)
          nblock = n;
        }
     
      send[3] = 0x01;
      n = 2*nlen + 5;
      send[4] = (n >> 8) & 0xFF;
      send[5] = n & 0xFF;
      k = 6;
      for(n = 0 ; n < nlen ; ++n)
        {
        send[k] = 0;
        send[k+1] = fname[n];
        k += 2;
        } 
      send[k] = 0;
      send[k+1] = 0;
      k += 2;
    
      send[k] = 0xC3;
      send[k+1] = (flen >> 24) & 0xFF;
      send[k+2] = (flen >> 16) & 0xFF;
      send[k+3] = (flen >> 8) & 0xFF;
      send[k+4] = flen & 0xFF;
      k += 5;
      err = 0;
      do
        { 
        if(ntogo <= nblock - 3 - k)
          {
          send[k] = 0x49;
          send[0] = 0x82;
          ndat = ntogo + 3;
          }
        else
          {
          send[k] = 0x48;
          send[0] = 0x02;
          ndat = nblock - k;
          } 
        send[k+1] = (ndat >> 8) & 0xFF;
        send[k+2] = ndat & 0xFF;
        k += 3;
        ndat -= 3;
        if(fread(send+k,1,ndat,stream) != ndat)
          {
          printf("File read error\n");
          err = 1;
          }
        else
          {
          ntogo -= ndat;
          k += ndat;
          send[1] = (k >> 8) & 0xFF;
          send[2] = k & 0xFF;
          write_node(node,send,k);  // send k bytes
          inbuf[0] = 0;
          len = read_node_endchar(node,inbuf,64,PACKET_ENDCHAR,EXIT_TIMEOUT,5000);
          if(len == 0 || (inbuf[0] != 0xA0 && inbuf[0] != 0x90))
            {
            printf("Send failed\n");
            err = 1;
            }
          }  
        k = 3;
        }
      while(ntogo > 0 && err == 0);  
    
      fclose(stream);
      
      write_node(node,disconnect,3);
      inbuf[0] = 0;
      len = read_node_endchar(node,inbuf,64,PACKET_ENDCHAR,EXIT_TIMEOUT,5000);
      if(len == 0 || inbuf[0] != 0xA0)
        printf("OBEX Disconnect failed\n");
    
      return(1);
      }