obex 源码阅读笔记1 handle初始化和connect处理

阅读的是apps/obex_test/obex_test.c
它的功能是:根据用户的输入,执行不同的opcode
" c - connect\n"
" d - disconnect\n"
" g - get\n"
" p - put\n"
" t - set path\n"
" s - server\n"
" x - push\n"
" h - help\n"
" q - quit\n"

笔记分2部分:

1,main函数初始化handel部分的代码分析

2,connect部分的代码分析

以下是简要分析:

最大的结构体:

obex_main.h
struct obex {
        uint16_t mtu_tx;                /* Maximum OBEX TX packet size */
        uint16_t mtu_rx;                /* Maximum OBEX RX packet size */
        uint16_t mtu_tx_max;            /* Maximum TX we can accept */

        enum obex_state state;
        enum obex_substate substate;
        enum obex_mode mode;
        enum obex_rsp_mode rsp_mode;    /* OBEX_RSP_MODE_* */

        unsigned int init_flags;
        unsigned int srm_flags;         /* Flags for single response mode */

        struct databuffer *tx_msg;      /* Reusable transmit message */
        struct databuffer *rx_msg;      /* Reusable receive message */

        struct obex_object *object;     /* Current object being transfered */
        obex_event_t eventcb;           /* Event-callback */
        enum obex_event abort_event;    /**< event for application when server aborts */

        obex_transport_t *trans;        /* Transport being used */

        obex_interface_t *interfaces;   /* Array of discovered interfaces */
        int interfaces_number;          /* Number of discovered interfaces */

        void * userdata;                /* For user */
};

工具函数:

1,把字符串转换成蓝牙地址

参考:https://nxmnpg.lemoda.net/3/bt_aton

#define bdaddr_t unsigned long

int bt_aton(const char *str, bdaddr_t *ba);
The bt_aton() routine interprets the specified character string as a Bluetooth address, placing the address into the structure provided. It returns 1 if the string was successfully interpreted, or 0 if the string is invalid.

返回值是1,说明是合法的地址,并把地址放入ba

例子:

const char *bdstr = "00:01:02:03:04:05";
bdaddr_t bd;
struct hostent *hp;

if (!bt_aton(bdstr, &bd))
        errx(1, "can't parse BD_ADDR %s", bdstr);


if ((hp = bt_gethostbyaddr((const char *)&bd,
    sizeof(bd), AF_BLUETOOTH)) == NULL)
        errx(1, "no name associated with %s", bdstr);


printf("name associated with %s is %s\n", bdstr, hp->h_name);

1,main函数初始化handle

main函数,要设置 obex_t *handle,

用函数api.c:OBEX_Init(OBEX_TRANS_BLUETOOTH, obex_event,flags)初始化 handle

  • obex_main.c:obex_library_init:读取环境变量"OBEX_DEBUG","OBEX_DUMP",设置全局变量obex_debug,obex_dump

  • obex_main.c:obex_create:开辟handle的内存空间,并设置

    self->eventcb = eventcb;//回调函数,定义在obex_test.c:obex_event函数
    self->init_flags = flags;
    self->mode = OBEX_MODE_SERVER;
    self->state = STATE_IDLE;
    self->rsp_mode = OBEX_RSP_MODE_NORMAL;
    
    /* Safe values.
    * Both self->mtu_rx and self->mtu_tx_max can be increased by app
    * self->mtu_tx will be whatever the other end sends us - Jean II */
    self->mtu_tx = OBEX_MINIMUM_MTU;//255
    
  • obex_transport.c:bool obex_transport_init(obex_t *self, int transport):初始化self的trans如下代码:

    trans结构体(obex_transport_t)里,有结构体obex_transport_ops(定义如下),里面定义了各种业务函数。

    struct obex {
        ...
        obex_transport_t *trans;        /* Transport being used */
        ...
    }
    typedef struct obex_transport {
            struct obex_transport_ops *ops;
            void *data;             /* Private data for the transport */
            int64_t timeout;        /* set timeout */
            bool connected;         /* Link connection state */
            bool server;            /* Listens on local interface */
    } obex_transport_t;
    
    struct obex_transport_ops {
            void * (*create)(void);
            bool (*init)(obex_t*);
            void (*cleanup)(obex_t*);
    
            result_t (*handle_input)(obex_t*);
            ssize_t (*write)(obex_t*, struct databuffer*);
            ssize_t (*read)(obex_t*, void*, int);
            bool (*disconnect)(obex_t*);
    
            int (*get_fd)(obex_t*);
            bool (*set_local_addr)(obex_t*, struct sockaddr*, size_t);
            bool (*set_remote_addr)(obex_t*, struct sockaddr*, size_t);
    
            struct {
                    bool (*listen)(obex_t*);
                    bool (*accept)(obex_t*, const obex_t*);
            } server;
    
            struct {
                    bool (*connect)(obex_t*);
                    int (*find_interfaces)(obex_t*, obex_interface_t**);
                    void (*free_interface)(obex_interface_t*);
                    bool (*select_interface)(obex_t*, obex_interface_t*);
            } client;
    };
    

    btobex.c:btobex_transport_create函数,返回obex_transport

    obex_transport.c:obex_transport_create函数,参数类型:struct obex_transport_ops,参数的值:

    btobex.c
    static struct obex_transport_ops btobex_transport_ops = {
            &btobex_create,
            &btobex_init,
            &btobex_cleanup,
    
            &btobex_handle_input,
            &btobex_write,
            &btobex_read,
            &btobex_disconnect,
    
            &btobex_get_fd,
            &btobex_set_local_addr,
            &btobex_set_remote_addr,
    
            {
                    &btobex_listen,
                    &btobex_accept,
            },
    
            {
                    &btobex_connect_request,
                    NULL,
                    NULL,
                    NULL,
            },
    };
    

    里面的函数都定义在btobex.c里面。

    开辟trans的内存空间,并设置ops,data等属性,调用ops里的create函数,来初始化trans->data

    trans->ops = ops;
    trans->data = NULL;
    if (ops->create)
      trans->data = ops->create();//return calloc(1, sizeof(struct btobex_rfcomm_data));
    
    trans->timeout = -1; /* no time-out */
    trans->connected = false;
    trans->server = false;
    
    return trans;
    
    btobex.c
    struct btobex_rfcomm_data {
            struct obex_sock *sock;
    };
    obex_transport_sock.h
    struct obex_sock {
            /** socket domain */
            int domain;
            /** socket protocol */
            int proto;
            /** the kernel descriptor for this socket */
            socket_t fd;
            /** the local address of this socket */
            struct sockaddr_storage local;
            /** the remote address of this socket */
            struct sockaddr_storage remote;
            /** the address size of this socket type */
            socklen_t addr_size;
            /** socket OBEX_FL_* flags */
            unsigned int flags;
            /** callback to set transport-specific socket options */
            bool (*set_sock_opts)(socket_t);
    };
    
  • 初始化trans后,调用self->trans->ops->init(self),初始化self->trans->data里的sock结构体

    init执行的函数是btobex.c:btobex_init函数

    static bool btobex_init(obex_t *self)
    {
            struct btobex_rfcomm_data *data = self->trans->data;
            socklen_t len = sizeof(struct sockaddr_rc);
    
            if (data == NULL)
                    return false;
    
            data->sock = obex_transport_sock_create(AF_BLUETOOTH, BTPROTO_RFCOMM,
                                                    len, self->init_flags);
            if (data->sock == NULL) {
                    free(data);
                    return false;
            }
    
            return true;
    }
    

    obex_trnasport_sock.c:obex_transport_sock_create函数,初始化self->trans->data里的sock结构体

    struct obex_sock * obex_transport_sock_create(int domain, int proto,
                                                  socklen_t addr_size,
                                                  unsigned int flags)
    {
            struct obex_sock *sock = calloc(1, sizeof(*sock));
    #define SAVE_FLAGS (OBEX_FL_CLOEXEC | OBEX_FL_NONBLOCK | OBEX_FL_KEEPSERVER)
    
            DEBUG(4, "\n");
    
            if (sock == NULL)
                    return NULL;
    
            sock->domain = domain;
            sock->proto = proto;
            sock->addr_size = addr_size;
            sock->flags = flags & SAVE_FLAGS;
            sock->fd = INVALID_SOCKET;//-1
    
            return sock;
    }
    
    

    返回到api.c:OBEX_Init,至此obex_t的handle初始化完毕,执行到:

     switch (btobex) {
                    case TRUE:
                            printf("Using Bluetooth RFCOMM transport\n");
                            handle = OBEX_Init(OBEX_TRANS_BLUETOOTH, obex_event,
                                              flags);
                            if (channel_arg)
                                    channel = (atoi(channel_arg) & 0xFF);
                            else
                                    channel = BT_CHANNEL;
                            break;
    
  • 然后main里执行:api.cl里的OBEX_SetUserData(handle, &global_context);

    目的:设置handle里的userdata,这里data的值是NULL。

    self->userdata=data;
    
  • 之后进入while循环:等待用户的输入

     while (!end) {
                    if (read_input(cmd, sizeof(cmd), "> ") < 0)
                            break;
                    switch(cmd[0]) {
                            case 'h':
                                    printf("Commands:\n"
                                           " c - connect\n"
                                           " d - disconnect\n"
                                           " g - get\n"
                                           " p - put\n"
                                           " t - set path\n"
                                           " s - server\n"
                                           " x - push\n"
                                           " h - help\n"
                                           " q - quit\n"
    

2, connect

当用户输入c,则调用下面的:1和2

1,api.c的函数:int CALLAPI BtOBEX_TransportConnect,

  • 参数:

    • handle
    • BDADDR_ANY:src
    • &bdaddr:dst
    • channel:类似tcp的端口号
  • 调用btobex.c:btobex_prepare_connect(self, src, dst, channel);

    • 调用btobex.c:btobex_prepare_listen(obex_t *self, const bdaddr_t *src, uint8_t channel)

      • 调用btobex_addr2sock(const bdaddr_t *addr, uint8_t channel,struct sockaddr_rc *sock)

        设置sock

      • 调用obex_transport_sock_set_local(data->sock, (struct sockaddr *) &sock,sizeof(sock));

        设置data->socklocal

        memcpy(&sock->local, addr, len);

  • 调用obex.trnasport.c:obex_transport_connect_request(self)

    调用self->trans->ops->client.connect(self)函数,就是调用btobex.c:btobex_connect_request

    • 调用obex_transport_sock.c:obex_transport_sock_connect

      创建sock->fd:obex:transport_sock.c:create_stream_socket

      obex:transport_sock.c
      socket_t create_stream_socket(int domain, int proto, unsigned int flags)
      {
              int type = SOCK_STREAM;
              socket_t fd;
      
              if (flags & OBEX_FL_CLOEXEC)
                      fd = socket_cloexec(domain, type, proto);
              else
                      fd = socket(domain, type, proto);
      
              if (flags & OBEX_FL_NONBLOCK)
                      socket_set_nonblocking(fd);
      
              return fd;
      }
      

      检查sock->set_sock_opts(回调函数),是否被设置,它是没有被设置的。

      最后真正去连接对端

      ret = connect(fd, (struct sockaddr*) &sock->remote, sock->addr_size);
      

      到此为止,已经和对端建立了连接。之后就要发送数据包了。

2,obex_test_client.c:connect_client(obex_t *handle),它再调用api.c的下面的函数

object = OBEX_ObjectNew(handle, OBEX_CMD_CONNECT);

obex_object结构体定义:

obex_object.h
struct obex_object {
        struct databuffer *tx_nonhdr_data;      /* Data before of headers (like CONNECT and SETPATH) */
        struct databuffer_list *tx_headerq;     /* List of headers to transmit*/
        struct obex_hdr_it *tx_it;

        struct databuffer *rx_nonhdr_data;      /* Data before of headers (like CONNECT and SETPATH) */
        struct databuffer_list *rx_headerq;     /* List of received headers */
        struct obex_hdr_it *rx_it;
        struct obex_hdr_it *it;

        enum obex_cmd cmd;              /* command */
        enum obex_rsp rsp;              /* response */
        enum obex_rsp lastrsp;          /* response for last packet */

        uint16_t headeroffset;          /* Where to start parsing headers */
        uint32_t hinted_body_len;       /* Hinted body-length or 0 */
        bool abort;                     /* Request shall be aborted */

        enum obex_rsp_mode rsp_mode;    /* OBEX_RSP_MODE_* */

        bool suspended;                 /* Temporarily stop transfering object */

        struct obex_hdr *body;          /* The body header need some extra help */
        struct obex_body *body_rcv;     /* Deliver body */
};

struct databuffer {
        struct databuffer_ops *ops;
        void *ops_data;
};
/** This implements an abstracted data buffer. */
struct databuffer_ops {
        void* (*new)(size_t default_size);
        void (*delete)(void *self);
        size_t (*get_offset)(void *self);
        void (*set_offset)(void *self, size_t offset);
        size_t (*get_size)(void *self);
        int (*set_size)(void *self, size_t new_size);
        size_t (*get_length)(const void *self);
        void *(*get)(const void *self);
        void (*clear)(void *self, size_t len);
        int (*append)(void *self, const void *data, size_t len);
};

struct obex_hdr_it {
        struct databuffer_list *list;
        int is_valid;
};
/*
 * Implements a single linked list
 */
struct databuffer_list {
        void *data;
        struct databuffer_list *next;
};

struct obex_hdr {
        unsigned int flags;
        size_t offset;
        struct obex_hdr_ops *ops;
        void *data;
};
struct obex_hdr_ops {
        void (*destroy)(void *self);
        enum obex_hdr_id (*get_id)(void *self);
        enum obex_hdr_type (*get_type)(void *self);
        size_t (*get_data_size)(void *self);
        const void * (*get_data_ptr)(void *self);
        bool (*set_data)(void *self, const void *data, size_t size);
        size_t (*append_data)(void *self, struct databuffer *buf, size_t size);
        bool (*is_finished)(void *self);
};

struct obex_body {
        struct obex_body_ops *ops;
        void *data;
};

struct obex_body_ops {
        int (*rcv)(void *data, struct obex_hdr *hdr);
        const void * (*read)(void *data, size_t *size);
};

调用connect_client

obex_test_client.c
void connect_client(obex_t *handle)
{
        obex_object_t *object;
        obex_headerdata_t hd;
        int err;

        object = OBEX_ObjectNew(handle, OBEX_CMD_CONNECT);//0x00 opcode是CONNECTION
        if(object == NULL) {
                printf("Error\n");
                return;
        }

        hd.bs = (uint8_t *) "Linux";
        if(OBEX_ObjectAddHeader(handle, object, OBEX_HDR_WHO, hd, 6,
                                OBEX_FL_FIT_ONE_PACKET) < 0)
        {
                printf("Error adding header\n");
                OBEX_ObjectDelete(handle, object);
                return;
        }
        err = OBEX_Request(handle, object);
        if (err) {
                OBEX_ObjectDelete(handle, object);
                printf("Error: %s\n", strerror(err));
                return;
        }
        syncwait(handle);
}

OBEX_ObjectNew

api.c
LIB_SYMBOL
obex_object_t * CALLAPI OBEX_ObjectNew(obex_t *self, uint8_t cmd)
{
        obex_object_t *object;

        obex_return_val_if_fail(self != NULL, NULL);

        //开辟内存,设置了rsp和lastrsp两个字段
        object = obex_object_new();
        if (object == NULL)
                return NULL;

        //设置opcode
        obex_object_setcmd(object, cmd);
        /* Need some special woodoo magic on connect-frame */
        if (cmd == OBEX_CMD_CONNECT) {
                //往object里添加需要发送的数据
                if (obex_insert_connectframe(self, object) < 0) {
                        obex_object_delete(object);
                        object = NULL;
                }
        }

        return object;
}
/*
 * Function obex_object_setcmd ()
 *
 *    Set command of object
 *
 */
void obex_object_setcmd(obex_object_t *object, enum obex_cmd cmd)
{
        DEBUG(4,"%02x\n", cmd);
        object->cmd = cmd & ~OBEX_FINAL;
}

obex_connect.c
#pragma pack(1)//按1字节位单位,做字节对齐。目的是让结构体的元素之间没有空隙。
struct obex_connect_hdr {
        uint8_t  version;
        uint8_t  flags;
        uint16_t mtu;
};
#pragma pack()//恢复原来的字节对齐方式

int obex_insert_connectframe(obex_t *self, obex_object_t *object)
{
        struct databuffer *buf = object->tx_nonhdr_data;
        struct obex_connect_hdr *hdr;

        DEBUG(4, "\n");

        if (!buf) {
                buf = object->tx_nonhdr_data = membuf_create(sizeof(*hdr));
                if (!buf)
                        return -1;
        } else
                buf_clear(buf, buf_get_length(buf));

        buf_append(buf, NULL, sizeof(*hdr));
        hdr = buf_get(buf);//让hdr指向了buf里的object->ops_data,所以后面设置hdr的字段就是设置ops_data里的字段了。
        hdr->version = OBEX_VERSION;
        hdr->flags = 0x00;              /* Flags */
        hdr->mtu = htons(self->mtu_rx); /* Max packet size */
        return 0;
}
/*
 * Function obex_object_new ()
 *
 *    Create a new OBEX object
 *
 */
obex_object_t *obex_object_new(void)
{
        obex_object_t *object = calloc(1, sizeof(*object));

        if (object != NULL)
                obex_object_setrsp(object, OBEX_RSP_NOT_IMPLEMENTED,
                                                OBEX_RSP_NOT_IMPLEMENTED);

        return object;
}
/*
 * Function obex_object_setrsp ()
 *
 *    Set the response for an object
 *
 */
int obex_object_setrsp(obex_object_t *object, enum obex_rsp rsp,
                       enum obex_rsp lastrsp)
{
        DEBUG(4,"\n");
        object->rsp = rsp;
        object->lastrsp = lastrsp;
        return 1;
}

创建databuffer结构体

membuf.c
[-] membuf.c
 {-} Functions
   +> membuf_set_size()
   +> membuf_new()
   +> membuf_delete()
   +> membuf_get_offset()
   +> membuf_set_offset()
   +> membuf_get_size()
   +> membuf_get_length()
   +> membuf_get()
   +> membuf_clear()
   +> membuf_append()
   +> membuf_create()

static struct databuffer_ops membuf_ops = {
        &membuf_new,
        &membuf_delete,
        &membuf_get_offset,
        &membuf_set_offset,
        &membuf_get_size,
        &membuf_set_size,
        &membuf_get_length,
        &membuf_get,
        &membuf_clear,
        &membuf_append,
};

struct databuffer *membuf_create(size_t default_size) {
        //使用membuf_ops初始化databuffer->ops部分;
        //使用 self->ops->new(default_size),初始化databuffer->ops_data
        return buf_create(default_size, &membuf_ops);
}

databuffer.c
struct databuffer *buf_create(size_t default_size, struct databuffer_ops *ops) {
        struct databuffer *self = malloc(sizeof(*self));

        if (!self)
                return NULL;

        self->ops = ops;
        self->ops_data = self->ops->new(default_size);//调用的是membuf_new函数
        if (!self->ops_data) {
                free(self);
                return NULL;
        }

        return self;
}

struct membuf_data {
        uint8_t *buffer;
        size_t buffer_size;

        size_t offset;
        size_t data_len;
};
static void *membuf_new(size_t default_size) {
        struct membuf_data *p;

        p = malloc(sizeof(*p));
        if (!p)
                return NULL;

        p->buffer = NULL;
        p->buffer_size = 0;
        p->offset = 0;
        p->data_len = 0;

        if (membuf_set_size(p, default_size) < 0) {
                free(p);
                p = NULL;
        }

        return (void*)p;
}

函数OBEX_ObjectNew之后是,执行函数OBEX_ObjectAddHeader

api.c
LIB_SYMBOL
int CALLAPI OBEX_ObjectAddHeader(obex_t *self, obex_object_t *object, uint8_t hi,
                                obex_headerdata_t hv, uint32_t hv_size,
                                unsigned int flags)
{
        obex_return_val_if_fail(self != NULL, -1);
        obex_return_val_if_fail(object != NULL, -1);
        return obex_object_addheader(self, object, hi, hv, hv_size, flags);
}

obex_object_addheader函数

当hi为who时,type为OBEX_HDR_TYPE_BYTES

obex_object.c
int obex_object_addheader(obex_t *self, obex_object_t *object, uint8_t hi,
                                obex_headerdata_t hv, uint32_t hv_size,
                                unsigned int flags)
{
        int ret;
        struct obex_hdr *hdr;
        const void *value;
        uint32_t bq4;
        size_t size;
        enum obex_hdr_id id = hi & OBEX_HDR_ID_MASK;
        enum obex_hdr_type type = hi & OBEX_HDR_TYPE_MASK;
        unsigned int flags2 = OBEX_FL_COPY;

        DEBUG(4, "\n");

        if (object == NULL)
                object = self->object;
        if (object == NULL)
                return -1;

        if (id == OBEX_HDR_ID_BODY_END)
        {
                id = OBEX_HDR_ID_BODY;
                if (object->body)
                        flags &= OBEX_FL_STREAM_DATAEND;
        }

        if (id == OBEX_HDR_ID_BODY) {
                if (flags & OBEX_FL_STREAM_DATAEND) {
                        /* End of stream marker */
                        if (object->body == NULL) {
                                /* A body with a single chunk. */
                                hdr = obex_hdr_ptr_create(OBEX_HDR_ID_BODY_END, OBEX_HDR_TYPE_BYTES, hv.bs, hv_size);
                                hdr = obex_hdr_stream_create(self, hdr);
                                obex_hdr_stream_finish(hdr);
                        } else {
                                /* Set the remaining data on the BODY header... */
                                obex_hdr_set_data(object->body, hv.bs, hv_size);
                                obex_hdr_stream_finish(object->body);
                                object->body = NULL;
                                /* ...and add the BODY_END header to the end */
                                hdr = obex_hdr_ptr_create(OBEX_HDR_ID_BODY_END,
                                                          OBEX_HDR_TYPE_BYTES, NULL, 0);
                        }
                        ret = 1;
                        goto out;

                } else if (flags & OBEX_FL_STREAM_CONTINUE) {
                        /* Continue stream after all other headers */
                        if (object->body == NULL)
                                return -1;
                        obex_hdr_stream_finish(object->body);
                        hdr = obex_hdr_ptr_create(id, OBEX_HDR_TYPE_BYTES, hv.bs, hv_size);
                        hdr = obex_hdr_stream_create(self, hdr);
                        object->body = hdr;
                        ret = 1;
                        goto out;

                } else if (flags & OBEX_FL_STREAM_DATA) {
                        /* Stream data */
                        if (object->body == NULL)
                                return -1;
                        obex_hdr_set_data(object->body, hv.bs, hv_size);
                        return 1;

                } else if (flags & OBEX_FL_STREAM_START) {
                        /* Is this a stream? */
                        DEBUG(3, "Adding stream\n");
                        if (object->body)
                                return -1;
                        hdr = obex_hdr_ptr_create(id, OBEX_HDR_TYPE_BYTES, hv.bs, hv_size);
                        hdr = obex_hdr_stream_create(self, hdr);
                        object->body = hdr;
                        ret = 1;
                        goto out;
                }
        }

        switch (type) {
        case OBEX_HDR_TYPE_UINT32:
                DEBUG(2, "4BQ header %d\n", hv.bq4);
                bq4 = htonl(hv.bq4);
                value = &bq4;
                size = 4;
                break;

        case OBEX_HDR_TYPE_UINT8:
                DEBUG(2, "1BQ header %d\n", hv.bq1);
                value = &hv.bq1;
                size = 1;
                break;

        case OBEX_HDR_TYPE_BYTES:
                DEBUG(2, "BS  header size %d\n", hv_size);
                value = hv.bs;
                size = hv_size;
                break;

        case OBEX_HDR_TYPE_UNICODE:
                DEBUG(2, "Unicode header size %d\n", hv_size);
                value = hv.bs;
                size = hv_size;
                break;

        default:
                return -1;
        }

        if (hi == OBEX_HDR_EMPTY) {
                DEBUG(2, "Empty header\n");
                id = OBEX_HDR_ID_INVALID;
                type = OBEX_HDR_TYPE_INVALID;
                value = NULL;
                size = 0;
                flags2 = 0;
        }

        flags2 |= (flags & OBEX_FL_SUSPEND);
        hdr = obex_hdr_create(id, type, value, size, flags2);
        if (!hdr)
                return -1;

        ret = (int)obex_hdr_get_size(hdr);
        /* Check if you can send this header without violating MTU or
         * OBEX_FIT_ONE_PACKET */
        if (!obex_hdr_is_splittable(hdr) && (flags & OBEX_FL_FIT_ONE_PACKET)) {
                int maxlen = obex_msg_getspace(self, object, flags);
                if (maxlen < ret) {
                        DEBUG(0, "Header to big\n");
                        obex_hdr_destroy(hdr);
                        return -1;
                }
        }

out:
        //开辟tx_headerq空间,它是单向链表,存放header
        object->tx_headerq = slist_append(object->tx_headerq, hdr);

        //开辟tx_it空间,让tx_it->list指向tx_headerq
        if (object->tx_it == NULL)
                object->tx_it = obex_hdr_it_create(object->tx_headerq);

        return ret;
}
struct obex_hdr_it {
        struct databuffer_list *list;
        int is_valid;
};

obex_object_addheader调用obex_hdr_create

obex_hdr.c
struct obex_hdr * obex_hdr_create(enum obex_hdr_id id, enum obex_hdr_type type,
                                  const void *value, size_t size,
                                  unsigned int flags)
{
        struct obex_hdr *hdr;
        const unsigned int save_flags = OBEX_FL_SUSPEND;//值为(1 <<  4)

        if (flags & OBEX_FL_COPY)
                //开辟obex_hdr的内存空间,和obex_hdr->data的内存空间
                hdr = obex_hdr_membuf_create(id, type, value, size);
        else
                hdr = obex_hdr_ptr_create(id, type, value, size);

        if (!hdr)
                return NULL;
        //设置hdr的flags,在原来的基础上加上了OBEX_FL_SUSPEND
        hdr->flags |= (flags & save_flags);
        return hdr;
}

obex_hdr_create调用obex_hdr_membuf_create

1,先开辟obex_hdr->data的内存空间(通过调用obex_hdr_membuf_new)

2,开辟obex_hdr的内存空间,并让obex_hdr->data等于1,的返回值。

obex_hdr.membuf.c
struct obex_hdr * obex_hdr_membuf_create(enum obex_hdr_id id,
                                         enum obex_hdr_type type,
                                         const void *data, size_t size)
{
        void *buf = obex_hdr_membuf_new(id, type, data, size);

        if (!buf)
                return NULL;

        return obex_hdr_new(&obex_hdr_membuf_ops, buf);
}

obex_hdr_membuf_create调用obex_hdr_membuf_new

obex_hdr.membuf.c
static
void * obex_hdr_membuf_new(enum obex_hdr_id id, enum obex_hdr_type type,
                           const void *value, size_t size)
{
        struct obex_hdr_membuf *hdr = malloc(sizeof(*hdr));

        if (!hdr)
                return NULL;

        hdr->id = id;
        hdr->type = type;
        hdr->buf = membuf_create(size);
        if (hdr->buf == NULL) {
                free(hdr);
                return NULL;
        }

        buf_append(hdr->buf, value, size);
        return hdr;
}

obex_hdr_membuf_create调用obex_hdr_new

struct obex_hdr * obex_hdr_new(struct obex_hdr_ops *ops, void *data)
{
        struct obex_hdr *hdr = calloc(1, sizeof(*hdr));
        if (!hdr) {
                if (ops && ops->destroy)
                        ops->destroy(data);
                return NULL;
        }
        hdr->ops = ops;
        hdr->data = data;
        return hdr;
}

obex_object_addheader调用obex_hdr_get_size

返回hi + hv的大小

size_t obex_hdr_get_size(struct obex_hdr *hdr)
{
        size_t hdr_size = obex_hdr_get_hdr_size(hdr);
        size_t data_size = obex_hdr_get_data_size(hdr);

        return hdr_size + data_size;
}

调用OBEX_Request

api.c
LIB_SYMBOL
int CALLAPI OBEX_Request(obex_t *self, obex_object_t *object)
{
        result_t result;

        DEBUG(4, "\n");

        obex_return_val_if_fail(self != NULL, -EINVAL);
        obex_return_val_if_fail(object != NULL, -EINVAL);

        if (self->object) {
                DEBUG(1, "We are busy.\n");
                return -EBUSY;
        }

        object->rsp_mode = self->rsp_mode;
        self->object = object;
        self->mode = OBEX_MODE_CLIENT;
        self->state = STATE_REQUEST;
        self->substate = SUBSTATE_TX_PREPARE;

        /* Prepare the packet but do not send it */
        result = obex_client(self);
        if (result < 0) {
                self->object = NULL;
                self->mode = OBEX_MODE_SERVER;
                self->state = STATE_IDLE;
                return -EIO;
        }

        return 0;
}

OBEX_Request调用obex_client,参数:self->state为STATE_REQUEST;self->substate为SUBSTATE_TX_PREPARE

obex_client.c
result_t obex_client(obex_t *self)
{
        DEBUG(4, "\n");

        switch (self->state) {
        case STATE_REQUEST:
                switch (self->substate) {
                case SUBSTATE_RX:
                        return obex_client_request_rx(self);

                case SUBSTATE_TX_PREPARE:
                        return obex_client_request_tx_prepare(self);

                case SUBSTATE_TX:
                        return obex_client_request_tx(self);

                default:
                        break;
                }
                break;

        case STATE_RESPONSE:
                switch (self->substate) {
                case SUBSTATE_RX:
                        return obex_client_response_rx(self);

                case SUBSTATE_TX_PREPARE:
                        return obex_client_response_tx_prepare(self);

                case SUBSTATE_TX:
                        return obex_client_response_tx(self);

                default:
                        break;
                }
                break;

        case STATE_ABORT:
                switch (self->substate) {
                case SUBSTATE_RX:
                        return obex_client_abort_rx(self);

                case SUBSTATE_TX_PREPARE:
                        return obex_client_abort_tx_prepare(self);

                case SUBSTATE_TX:
                        return obex_client_abort_tx(self);

                default:
                        break;
                }
                break;

        default:
                DEBUG(0, "Unknown state\n");
                break;
        }

        return RESULT_ERROR;
}

obex_client调用obex_client_request_tx_prepare

obex_client.c
static result_t obex_client_request_tx_prepare(obex_t *self)
{
        DEBUG(4, "STATE: REQUEST/TX_PREPARE\n");

        if (self->object->abort) {
                self->state = STATE_ABORT;
                return obex_client_abort_tx_prepare(self);
        }

        if (!obex_msg_prepare(self, self->object, TRUE))
                return RESULT_ERROR;

        self->substate = SUBSTATE_TX;
        return RESULT_SUCCESS;
}

obex_client_request_tx_prepare调用obex_msg_prepare

obex_msg.c
bool obex_msg_prepare(obex_t *self, obex_object_t *object, bool allowfinal)
{
        buf_t *txmsg = self->tx_msg;
        uint16_t tx_left = self->mtu_tx - sizeof(struct obex_common_hdr);
        int real_opcode;
        struct obex_hdr_it it;

    	//用object->tx_it,设置it
        obex_hdr_it_init_from(&it, object->tx_it);

    	//初始化self->tx_msg
        if (!obex_data_request_init(self))
                return false;

        if (!obex_object_append_data(object, txmsg, tx_left))
                return false;

    	//得到opcode, 并判断是否加final bit
        real_opcode = obex_object_get_opcode(self->object, allowfinal,
                                             self->mode);
        DEBUG(4, "Generating packet with opcode %d\n", real_opcode);
    	//设置self->tx_msg里的opcode和length
        obex_data_request_prepare(self, real_opcode);

        return obex_msg_post_prepare(self, object, &it, object->tx_it);
}

obex_msg_prepare调用obex_data_request_init

obex_main.c
//初始化self->tx_msg
bool obex_data_request_init(obex_t *self)
{
        buf_t *msg = self->tx_msg;
        int err;

        buf_clear(msg, buf_get_length(msg));
        err = buf_set_size(msg, self->mtu_tx);
        if (err)
                return false;

        buf_append(msg, NULL, sizeof(struct obex_common_hdr));
        return true;
}

obex_msg_prepare调用obex_object_append_data

obex_object.c
//设置self->tx_msg
bool obex_object_append_data(obex_object_t *object, buf_t *txmsg, size_t tx_left)
{
        /* Don't do anything if object is suspended */
        if (object->suspended)
                return false;

        /* Add nonheader-data first if any (SETPATH, CONNECT)*/
        if (object->tx_nonhdr_data) {
                DEBUG(4, "Adding %lu bytes of non-headerdata\n",
                      (unsigned long)buf_get_length(object->tx_nonhdr_data));
                buf_append(txmsg, buf_get(object->tx_nonhdr_data),
                           buf_get_length(object->tx_nonhdr_data));

                buf_delete(object->tx_nonhdr_data);
                object->tx_nonhdr_data = NULL;
        }

        DEBUG(4, "4\n");

        /* Take headers from the tx queue and try to stuff as
         * many as possible into the tx-msg */
        if (object->tx_it) {
                bool has_body_header = false;
                struct obex_hdr *h = obex_hdr_it_get(object->tx_it);
                while (h != NULL && !object->suspended && tx_left > 0) {
                        enum obex_hdr_id id = obex_hdr_get_id(h);

                        if (id == OBEX_HDR_ID_BODY || id == OBEX_HDR_ID_BODY_END)
                        {
                                if (has_body_header)
                                        break;
                                has_body_header = true;
                        }

                        if (id != OBEX_HDR_ID_INVALID) {
                                size_t ret = obex_hdr_append(h, txmsg, tx_left);
                                if (ret == 0)
                                        break;
                                tx_left -= ret;
                        }

                        if (obex_hdr_is_finished(h)) {
                                if (h->flags & OBEX_FL_SUSPEND)
                                        object->suspended = true;

                                obex_hdr_it_next(object->tx_it);
                                h = obex_hdr_it_get(object->tx_it);
                        }
                }
        }

        return true;
}

obex_msg_prepare调用obex_object_get_opcode

obex_object.c
//得到opcode, 并判断是否加final bit
int obex_object_get_opcode(obex_object_t *object, bool allowfinal,
                           enum obex_mode mode)
{
        int opcode = -1;

        /* Decide which command to use, and if to use final-bit */
        DEBUG(4, "allowfinalcmd: %d mode:%d\n", allowfinal, mode);

        switch (mode) {
        case OBEX_MODE_SERVER:
                if (obex_object_finished(object, allowfinal))
                        opcode = object->lastrsp;
                else
                        opcode = object->rsp;
                opcode |= OBEX_FINAL;
                break;

        case OBEX_MODE_CLIENT:
                opcode = object->cmd;
                /* Have more headers (or body) to send? */
                if (obex_object_finished(object, allowfinal))
                        opcode |= OBEX_FINAL;
                break;

        default:
                break;
        }

        return opcode;
}

obex_msg_prepare调用obex_data_request_prepare

obex_main.c
void obex_data_request_prepare(obex_t *self, int opcode)
{
        buf_t *msg = self->tx_msg;
        obex_common_hdr_t *hdr = buf_get(msg);

        /* alignment is assured here */
        hdr->opcode = opcode;
        hdr->len = htons((uint16_t)buf_get_length(msg));

        DUMPBUFFER(1, "Tx", msg);
}
obex_main.h
/* Common header used by all frames */
#pragma pack(1)
struct obex_common_hdr {
        uint8_t  opcode;
        uint16_t len;
};
#pragma pack()
typedef struct obex_common_hdr obex_common_hdr_t;

obex_msg_prepare调用obex_msg_post_prepare

obex_msg.c
static bool obex_msg_post_prepare(obex_t *self, obex_object_t *object,
                                  const struct obex_hdr_it *from,
                                  const struct obex_hdr_it *to)
{
        struct obex_hdr_it it;
        struct obex_hdr *hdr;

        obex_hdr_it_init_from(&it, from);
        hdr = obex_hdr_it_get(&it);

        /* loop over all headers in that are non-NULL and finished... */
        while (hdr != NULL && obex_hdr_is_finished(hdr)) {
                if (self->rsp_mode == OBEX_RSP_MODE_SINGLE &&
                    obex_hdr_get_id(hdr) == OBEX_HDR_ID_SRM_FLAGS)
                {
                        const uint8_t *data = obex_hdr_get_data_ptr(hdr);

                        self->srm_flags &= ~OBEX_SRM_FLAG_WAIT_REMOTE;
                        self->srm_flags |= obex_srm_tx_flags_decode(data[0]);
                }

                /* ...but only in the range [from..to]. The last entry
                 * must be included if it is finished. */
                if (obex_hdr_it_equals(&it, to))
                        break;

                obex_hdr_it_next(&it);
                hdr = obex_hdr_it_get(&it);
        }

        return true;
}

connect_client调用syncwait

obex_test.h
struct context
{
        int serverdone;
        int clientdone;
        char *get_name; /* Name of last get-request */
};

obex_test_client.c
static void syncwait(obex_t *handle)
{
        struct context *gt;
        int ret;

        gt = OBEX_GetUserData(handle);

        while(!gt->clientdone) {
                //printf("syncwait()\n");
                ret = OBEX_HandleInput(handle, 10);
                if(ret < 0) {
                        printf("Error while doing OBEX_HandleInput()\n");
                        break;
                }
        }

        gt->clientdone = FALSE;
}

syncwait调用OBEX_HandleInput

api.c
IB_SYMBOL
int CALLAPI OBEX_HandleInput(obex_t *self, int timeout)
{
        int result;
        int64_t oldTimeout;
        enum obex_data_direction dir;

        obex_return_val_if_fail(self != NULL, -1);

        DEBUG(4, "\n");

        oldTimeout = obex_transport_get_timeout(self);
        //dir的值是OBEX_DATA_IN
        dir = obex_get_data_direction(self);
        obex_transport_set_timeout(self, timeout*1000);

        if (dir == OBEX_DATA_IN) {
                result = obex_work(self);
                if (result <= 0) /* timeout or error */
                        goto timeout_or_error;
                dir = obex_get_data_direction(self);
        }

        /* make the following loop more efficient */
        obex_transport_set_timeout(self, -1);

        while (dir == OBEX_DATA_NONE || dir == OBEX_DATA_OUT) {
                result = obex_work(self);
                if (result < 0) /* error */
                        goto timeout_or_error;
                dir = obex_get_data_direction(self);
        }

        result = 1;

timeout_or_error:
        obex_transport_set_timeout(self, oldTimeout);
        return result;
}

OBEX_HandleInput调用obex_get_data_direction

obex_main.c
enum obex_data_direction obex_get_data_direction(obex_t *self)
{
    	//在obex_main.c:obex_create里,self->state被设置成STATE_IDLE
        if (self->state == STATE_IDLE)
                return OBEX_DATA_IN;

        else if (self->substate == SUBSTATE_RX)
                return OBEX_DATA_IN;

        else if (self->substate == SUBSTATE_TX)
                return OBEX_DATA_OUT;

        else
                return OBEX_DATA_NONE;
}

OBEX_HandleInput调用obex_work

obex_main.c
/*
 * Function obex_work (self)
 *
 *    Do some work on the current transferred object.
 *
 */
result_t obex_work(obex_t *self)
{
        result_t ret;

        if (self->state == STATE_IDLE) {
                ret = obex_handle_input(self);
                if (ret != RESULT_SUCCESS)
                        return ret;

        } else if (self->substate == SUBSTATE_RX) {
                if (obex_check_srm_input(self)) {
                        ret = obex_handle_input(self);
                        if (ret != RESULT_SUCCESS)
                                return ret;
                }

        } else if (self->substate == SUBSTATE_TX) {
                if (!obex_msg_tx_status(self)) {
                        if (!obex_data_request_transmit(self)) {
                                enum obex_cmd cmd = OBEX_CMD_ABORT;

                                if (self->object)
                                        cmd = obex_object_getcmd(self->object);

                                obex_deliver_event(self, OBEX_EV_LINKERR, cmd,
                                                   0, TRUE);
                                self->mode = OBEX_MODE_SERVER;
                                self->state = STATE_IDLE;
                                return RESULT_ERROR;
                        }

                        if (!obex_msg_tx_status(self))
                                return RESULT_TIMEOUT;
                }
        }

        return obex_mode(self);
}

obex_work调用obex_handle_input

obex_main.c
result_t obex_handle_input(obex_t *self)
{
        result_t ret = obex_transport_handle_input(self);

        if (ret != RESULT_SUCCESS)
                return ret;

        if (obex_transport_is_server(self)) {
                DEBUG(4, "Data available on server socket\n");
                if (self->init_flags & OBEX_FL_KEEPSERVER)
                        /* Tell the app to perform the OBEX_Accept() */
                        obex_deliver_event(self, OBEX_EV_ACCEPTHINT, 0, 0, FALSE);

                else
                        obex_transport_accept(self, self);

                return RESULT_SUCCESS;

        } else {
                DEBUG(4, "Data available on client socket\n");
                return obex_data_indication(self);
        }
}

obex_handle_input调用obex_transport_handle_input

obex_transport.c
/*
 * Function obex_transport_handle_input(self)
 *
 *    Used when working in synchronous mode.
 *
 */
result_t obex_transport_handle_input(obex_t *self)
{
        DEBUG(4, "\n");
		//Check if the RX message buffer contains at least one full message.
        if (self->trans->connected && obex_msg_rx_status(self)) {
                DEBUG(4, "full message already in buffer\n");
                return RESULT_SUCCESS;
        }

    	//执行回调btobex.c里的函数btobex_handle_input
        if (self->trans->ops->handle_input)
                return self->trans->ops->handle_input(self);
        else
                return RESULT_ERROR;
}

obex_transport_handle_input调用btobex_handle_input

btobex.c
static result_t btobex_handle_input(obex_t *self)
{
        struct btobex_rfcomm_data *data = self->trans->data;

        DEBUG(4, "\n");

        return obex_transport_sock_wait(data->sock, self->trans->timeout);
}

btobex_handle_input调用obex_transport_sock_wait

这里的opcode是CONNECTING,为什么下面调用select函数阻塞等待对端的数据?

/** Wait for incoming data/events
 *
 * @param sock the socket instance
 * @param timeout give up after timeout (in milliseconds)
 * @return -1 on failure, 0 on timeout, >0 on success
 */
result_t obex_transport_sock_wait(struct obex_sock *sock, int64_t timeout)
{
        socket_t fd = sock->fd;
        fd_set fdset;
        int ret;

        DEBUG(4, "\n");

        /* Check of we have any fd's to do select on. */
        if (fd == INVALID_SOCKET) {
                DEBUG(0, "No valid socket is open\n");
                return RESULT_ERROR;
        }

        /* Add the fd's to the set. */
        FD_ZERO(&fdset);
        FD_SET(fd, &fdset);

        /* Wait for input */
        if (timeout >= 0) {
                struct timeval time = {(long)(timeout / 1000), (long)(timeout % 1000)};
                ret = select((int)fd + 1, &fdset, NULL, NULL, &time);
        } else {
                ret = select((int)fd + 1, &fdset, NULL, NULL, NULL);
        }

        /* Check if this is a timeout (0) or error (-1) */
        if (ret < 0)
                return RESULT_ERROR;
        else if (ret == 0)
                return RESULT_TIMEOUT;
        else
                return RESULT_SUCCESS;
}

其他的opcode处理都遵循下面的步骤

1,object = OBEX_ObjectNew(handle, OBEX_CMD_PUT);
2,OBEX_ObjectAddHeader(handle, object, OBEX_HDR_LENGTH, hd, 4, 0);
3,err = OBEX_Request(handle, object);
4,syncwait(handle);

c/c++ 学习互助QQ群:877684253

本人微信:xiaoshitou5854

posted @ 2020-07-14 11:17  小石王  阅读(431)  评论(0编辑  收藏  举报