zoukankan      html  css  js  c++  java
  • obex 源码阅读笔记1 handle初始化和connect处理

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

    笔记分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
    ", 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, "
      ");
      
              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
      ");
                              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:
      "
                                             " c - connect
      "
                                             " d - disconnect
      "
                                             " g - get
      "
                                             " p - put
      "
                                             " t - set path
      "
                                             " s - server
      "
                                             " x - push
      "
                                             " h - help
      "
                                             " q - quit
      "
      

    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
    ");
                    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
    ");
                    OBEX_ObjectDelete(handle, object);
                    return;
            }
            err = OBEX_Request(handle, object);
            if (err) {
                    OBEX_ObjectDelete(handle, object);
                    printf("Error: %s
    ", 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
    ", 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, "
    ");
    
            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,"
    ");
            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, "
    ");
    
            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
    ");
                            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
    ", hv.bq4);
                    bq4 = htonl(hv.bq4);
                    value = &bq4;
                    size = 4;
                    break;
    
            case OBEX_HDR_TYPE_UINT8:
                    DEBUG(2, "1BQ header %d
    ", hv.bq1);
                    value = &hv.bq1;
                    size = 1;
                    break;
    
            case OBEX_HDR_TYPE_BYTES:
                    DEBUG(2, "BS  header size %d
    ", hv_size);
                    value = hv.bs;
                    size = hv_size;
                    break;
    
            case OBEX_HDR_TYPE_UNICODE:
                    DEBUG(2, "Unicode header size %d
    ", hv_size);
                    value = hv.bs;
                    size = hv_size;
                    break;
    
            default:
                    return -1;
            }
    
            if (hi == OBEX_HDR_EMPTY) {
                    DEBUG(2, "Empty header
    ");
                    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
    ");
                            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, "
    ");
    
            obex_return_val_if_fail(self != NULL, -EINVAL);
            obex_return_val_if_fail(object != NULL, -EINVAL);
    
            if (self->object) {
                    DEBUG(1, "We are busy.
    ");
                    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, "
    ");
    
            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
    ");
                    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
    ");
    
            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
    ", 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
    ",
                          (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
    ");
    
            /* 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
    ", 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()
    ");
                    ret = OBEX_HandleInput(handle, 10);
                    if(ret < 0) {
                            printf("Error while doing OBEX_HandleInput()
    ");
                            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, "
    ");
    
            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
    ");
                    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
    ");
                    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, "
    ");
    		//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
    ");
                    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, "
    ");
    
            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, "
    ");
    
            /* Check of we have any fd's to do select on. */
            if (fd == INVALID_SOCKET) {
                    DEBUG(0, "No valid socket is open
    ");
                    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

  • 相关阅读:
    01 Jq 基础
    01 属性
    input 编辑框 光标 的相关问题
    登录页面 文字 2 3 4 个字 等宽俩端对齐 空格
    复选框单选框与文字对齐问题的研究与解决
    在Python中对MySQL中的数据进行可视化
    输入2个坐标的数值求出对应坐标间的距离和圆的面积
    numpy中arange函数内起始值必须大于结束值,否则生成为空的一维数组
    条件语句练习-比分预测
    三元表达式是棒棒哒!
  • 原文地址:https://www.cnblogs.com/xiaoshiwang/p/13298018.html
Copyright © 2011-2022 走看看