3.2. Socket interface

The Socket interface provides a standard, well-documented approach to access kernel network resources. The Affix brings to the system new protocol family PF_AFFIX and new socket address family "struct sockaddr_affix":

<affix/bluetooth.h> must be included to the source file.

Standard "socket" system call is used to create a socket of PF_AFFIX family:

int socket(PF_AFFIX, int type, int protocol);

where type parameter depends on the protocol parameter, which accepts following values:

3.2.1. Data structures

The Socket interface has only one data structure as any protocol family in Unix - cousin of sockaddr. The structure has a name "sockaddr_affix" and has the following prototype:

struct sockaddr_affix {
        sa_family_t     family;
        BD_ADDR         bda;
        uint16_t        port;
        BD_ADDR         local;
};
All fields except port has the same meaning for all protocols inside PF_AFFIX family. The "port" field has different meaning in for different protocols:

  • BTPROTO_L2CAP: "port" defines PSM value.

  • BTPROTO_RFCOMM: "port" defines server channel number.

  • BTPROTO_HCIACL and BTPROTO_HCISCO: "port" field is unused.

3.2.2. Function set

The PF_AFFIX socket family allows to use standard socket functions like connect(), bind(), listen(), accept(), send(), recv() and has additional Bluetooth and Affix specific extension. More details about socket call can be found in the UNIX manual pages.

The PF_AFFIX extension practically is implemented as ioctl() and set(get)sockopt() system calls, but for more convenient it is wrapped into the well-named functions.

The RFCOMM socket has additional feature: it can be bound to TTY line. The Affix uses "/dev/btyXX" names for that, where XX is a registered line. Special functions are used to do it:

3.2.3. Sample code

Practical examples can be found in the Affix source code. Here are examples showing how to use PF_AFFIX sockets on a client and a server sides.

The following example illustrates usage of the Affix socket interface on the client side.

#include <stdio.h>

/* Affix includes */
#include <affix/bluetooth.h>

int main(int argc, char *argv[])
{
     struct sockaddr_affix   sa;
     int  fd, err;

     fd = socket(PF_AFFIX, SOCK_SEQPACKET, BTPROTO_L2CAP);
     if (fd < 0) {
           perror("socket() failed");
           return 1;
     }

     sa.family = PF_AFFIX;
     str2bda(&sa.bda, "00:11:22:33:44:55");   /* connect to that device */
     /* or sa.bda = other_bda; */
     sa.port = 1;                             /* connect to that port (PSM) */ 
     sa.local = BDADDR_ANY;
     /*
        to connect through certain device use:
         sa.local = <local device bda>
     */

     err = connect(fd, (struct sockaddr*)&sa, sizeof(sa));
     if (err) {
           perror("connect() failed");
           return 2;
     }

     /* 
        here is socket is ready for communication
        any of the standard connection oriented 
        transmission/receiving system calls can be used.
        - send(), sendmsg(), write()
        - recv(), recvmsg(), read()
     */


     close(fd);

     return 0;
}
The next example illustrates usage of the socket interface on the server side.
#include <stdio.h>

/* Affix includes */
#include <affix/bluetooth.h>

int main(int argc, char *argv[])
{
     struct sockaddr_affix   sa, csa;
     int   fd, cfd, err;
     socklen_t csa_len;

     /* create server socket */
     fd = socket(PF_AFFIX, SOCK_SEQPACKET, BTPROTO_L2CAP);
     if (fd < 0) {
           perror("socket() failed");
           return 1;
     }

     sa.family = PF_AFFIX;
     sa.bda = BDADDR_ANY
     sa.port = 1;            /* accept connection to that port (PSM) */ 
     /*
        to connect through certain device use:
         sa.local = <local device bda>
     */

     /* bind socket to address specified by "sa" parameter */
     err = bind(fd, (struct sockaddr*)&sa, sizeof(sa));
     if (err) {
           perror("bind() failed");
           return 2;
     }

     /* start listen for connection - kernel will accept connection requests */
     err = listen(fd, 5)
     if (err) {
           perror("listen() failed");
           return 3;
     }

     /* accept new connection and get its connection descriptor "cfd" */
     csalen = sizeof(csa);
     cfd = accept(fd, (struct sockaddr*)&csa, &csa_len);
     if (cfd < 0) {
           perror("accept() failed");
           return 4;
     }

     /* 
        here is socket "cfd" is ready for communication
        any of the standard connection oriented 
        transmission/receiving system calls can be used.
        - send(), sendmsg(), write()
        - recv(), recvmsg(), read()
     */


     close(fd);  /* close server socket */
     close(cfd); /* close client socket */

     return 0;
}

3.2.4. Socket level security

All services operate above sockets, or at least connection establishment process is done above it. The Service Level security mode allows service to set its security level. It's done through a special security API.