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. It is a cousin of sockaddr. The structure has a name "sockaddr_affix" and has the following prototype:

struct sockaddr_affix {
    sa_family_t family;
    int         devnum;
    BD_ADDR     bda;
    uint16_t    port;
};
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:

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.

Table 3-4. PF_AFFIX extra API

FunctionApplicabilityPurpose
int l2cap_setmtu(int fd, int mtu);BTPROTO_L2CAPSets a maximum packet size that can be received on this socket. This function is used before calling connect() or bind().
int l2cap_getmtu(int fd);BTPROTO_L2CAPGets a maximum packet size that can be sent through this socket.
int hci_getmtu(int fd);BTPROTO_HCIACL, BTPROTO_HCISCOGets a maximum packet size that can be sent through this socket.
int l2cap_ping(int fd, char *data, int size);BTPROTO_L2CAPSends a *ping* packet and wait for response.

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:

Table 3-5. RFCOMM TTY API

FunctionPurpose
int rfcomm_open_tty(int fd, int line);Attaches an RFCOMM connection to a TTY line *line*. If the *line* is -1 then it allocates a unused tty line and returns its number.
int rfcomm_close_tty(int line);Detaches an RFCOMM connection from a TTY line *line* and close it.
int rfcomm_set_type(int fd, int type);Changes the RFCOMM socket type to: RFCOMM_SOCKET (default) or RFCOMM_BTY. This function has to be called right after *socket()*.
int rfcomm_bind_tty(int fd, struct sockaddr_affix *sa, int line)Binds an RFCOMM connection to a TTY line *line*. Connection is not established yet, but the line is reserved. When into the TTY is written the line is connected automatically.

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 Options

To set socket options use setsockopt() function. The definition for the function is:

int setsockopt(int fd, int level, int optname, void *optval, int *optlen);

Affix supports socket level SOL_AFFIX and the following table lists socket options.

Table 3-6. Supported socket options

OptionPurpose
BTSO_MTUSet the maximum transfer unit.
BTSO_SECURITYSet the 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. Possible modes are HCI_SECURITY_OPEN, HCI_SECURITY_AUTH, HCI_SECURITY_ENCRYPT, HCI_SECURITY_AUTHOR. Modes can bitwise-or'd
BTSO_EVENT_MASKDefines what events you want to handle. See possible values in hci_types.h
BTSO_PKT_MASKDefine what kind of packets socket should receive. Types are HCI_COMMAND, HCI_ACL, HCI_SCO, HCI_EVENT, HCI_PKT_OUTGOING and HCI_MGR. See definitions in hci_types.h.
BTSO_PROMISCAllow the socket to receive all the packets.
BTSO_TYPENot used

3.2.5. Python Support

Affix implements socket interface also for Python programing language. PyAffix package contains module for Python. It supports HCI, L2CAP, RFCOMM and non-blocking sockets. To use Affix with Python install Affix kernel module and make sure you have Python version 2.2.3 or later installed.

To installing Affix module in your Python do the following:

  1. Download latest PyAffix package from Affix web site (http://affix.sourceforge.net/pyaffix.shtml)

  2. Extract the downloaded tar ball and change to that directory

  3. Give the following command:

    python setup.py install

Also in Python you can use standard socket functions like connect(), bind(), listen(), accept(), send() and recv(). To create Affix socket you need to call socket() function like:

import affixsocket /* Just import Affix module and you are ready to use Affix */
affix_sock = socket(PF_AFFIX,SOCK_STREAM,BTPROTO_L2CAP)

Above example creates a new Affix socket object. Protocols and types are the same as listed in the beginning of this chapter. Connecting to remote host using newly created affix_sock object is done with connect method. The socket address information is represented in the following tuple in Python: (devnum, BTaddress, port). Where devnum is a positive integer representing the device, BTaddress is a string representing the Bluetooth address and port is the channel/psm/etc to connect to.

aff_sock.connect((0,"01:02:03:A0:B0:C0",1))

To set socket options use setsockopt(level, optname, value) method. See supported levels and options in chapter Section 3.2.4.