阅读的是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);