diff --git a/src/btstack.c b/src/btstack.c index 8859ad551..14b4ccd50 100644 --- a/src/btstack.c +++ b/src/btstack.c @@ -9,45 +9,23 @@ #include "btstack.h" #include "l2cap.h" +#include "socket_connection.h" #include "run_loop.h" -#include + #include #include #include - #include -typedef struct packet_header { - uint16_t length; - uint8_t type; - uint8_t data[0]; -} packet_header_t; - -typedef enum { - SOCKET_W4_HEADER, - SOCKET_W4_DATA, -} SOCKET_STATE; - -typedef struct connection { - data_source_t ds; // used for run loop - linked_item_t item; // used for connection list - SOCKET_STATE state; - uint16_t bytes_read; - uint16_t bytes_to_read; - uint8_t buffer[3+3+255]; // max HCI CMD + packet_header -} connection_t; - uint8_t hci_cmd_buffer[3+255]; uint8_t l2cap_sig_buffer[48]; - -static void dummy_handler(uint8_t *packet, int size); -static int btstack_socket_process(struct data_source *ds, int ready); - -static int btstack_socket = -1; static connection_t *btstack_connection = NULL; -static const int btstack_port = 1919; + +/** prototypes */ +static void dummy_handler(uint8_t *packet, int size); +int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size); /* callback to L2CAP layer */ static void (*event_packet_handler)(uint8_t *packet, int size) = dummy_handler; @@ -56,126 +34,44 @@ static void (*acl_packet_handler) (uint8_t *packet, int size) = dummy_handler; // init BTstack library int bt_open(){ - // TCP - struct protoent* tcp = getprotobyname("tcp"); - - btstack_socket = socket(PF_INET, SOCK_STREAM, tcp->p_proto); - if(btstack_socket == -1){ - return -1; - } - // localhost - struct sockaddr_in btdaemon_address; - btdaemon_address.sin_family = AF_INET; - btdaemon_address.sin_port = htons(btstack_port); - struct hostent* localhost = gethostbyname("localhost"); - if(!localhost){ - return -1; - } - // connect - char* addr = localhost->h_addr_list[0]; - memcpy(&btdaemon_address.sin_addr.s_addr, addr, sizeof addr); - if(connect(btstack_socket, (struct sockaddr*)&btdaemon_address, sizeof btdaemon_address) == -1){ - return -1; - } - - // register with run loop - btstack_connection = malloc( sizeof(connection_t)); - if (btstack_connection == NULL) return -1; - btstack_connection->ds.fd = btstack_socket; - btstack_connection->ds.process = btstack_socket_process; - run_loop_add(&btstack_connection->ds); - - // init state machine - btstack_connection->state = SOCKET_W4_HEADER; - btstack_connection->bytes_read = 0; - btstack_connection->bytes_to_read = sizeof(packet_header_t); - + socket_connection_register_packet_callback(btstack_packet_handler); + btstack_connection = socket_connection_open_tcp(); + if (!btstack_connection) return -1; return 0; } - // stop using BTstack library int bt_close(){ - if (btstack_socket < 0) return 0; - shutdown(btstack_socket, SHUT_RDWR); - if (btstack_connection) { - run_loop_remove(&btstack_connection->ds); - free( btstack_connection ); - btstack_connection = NULL; + return socket_connection_close_tcp(btstack_connection); +} + +int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size){ + switch (packet_type){ + case HCI_EVENT_PACKET: + (*event_packet_handler)(data, size); + break; + case HCI_ACL_DATA_PACKET: + (*acl_packet_handler)(data, size); + break; + default: + break; } return 0; } -// run_loop based data handling -int btstack_socket_process(struct data_source *ds, int ready) { - connection_t *conn = (connection_t *) ds; - int bytes_read = read(ds->fd, &conn->buffer[conn->bytes_read], conn->bytes_to_read); - if (bytes_read <= 0){ - // free - run_loop_remove(&conn->ds); - free(conn); - // TODO notify client of cailed daemon connection! - return 0; - } - conn->bytes_read += bytes_read; - conn->bytes_to_read -= bytes_read; - hexdump( conn->buffer, conn->bytes_read); - if (conn->bytes_to_read > 0) { - return 0; - } - switch (conn->state){ - case SOCKET_W4_HEADER: - conn->state = SOCKET_W4_DATA; - conn->bytes_to_read = READ_BT_16( conn->buffer, 0); - break; - case SOCKET_W4_DATA: - // process packet !!! - switch (conn->buffer[2]){ - case HCI_EVENT_PACKET: - (*event_packet_handler)(&conn->buffer[sizeof(packet_header_t)], READ_BT_16( conn->buffer, 0)); - break; - case HCI_ACL_DATA_PACKET: - (*acl_packet_handler)(&conn->buffer[sizeof(packet_header_t)], READ_BT_16( conn->buffer, 0)); - break; - default: - break; - } - - // wait for next packet - conn->state = SOCKET_W4_HEADER; - conn->bytes_read = 0; - conn->bytes_to_read = sizeof(packet_header_t); - break; - } - return 0; -} - - // send hci cmd packet int bt_send_cmd(hci_cmd_t *cmd, ...){ va_list argptr; va_start(argptr, cmd); uint16_t len = hci_create_cmd_internal(hci_cmd_buffer, cmd, argptr); va_end(argptr); - packet_header_t header; - bt_store_16( (uint8_t*) &header.length, 0, len); - header.type = HCI_COMMAND_DATA_PACKET; - hexdump( (uint8_t*)&header, sizeof(header)); - write(btstack_socket, (uint8_t*)&header, sizeof(header)); - hexdump( hci_cmd_buffer, len); - write(btstack_socket, hci_cmd_buffer, len); - return len; + socket_connection_send_packet(btstack_connection, HCI_COMMAND_DATA_PACKET, hci_cmd_buffer, len); + return 0; } // send hci acl packet int bt_send_acl_packet(uint8_t *packet, int size){ - packet_header_t header; - bt_store_16( (uint8_t*) &header.length, 0, size); - header.type = HCI_ACL_DATA_PACKET; - hexdump( (uint8_t*)&header, sizeof(header)); - write(btstack_socket, (uint8_t*)&header, sizeof(header)); - hexdump( hci_cmd_buffer, size); - write(btstack_socket, packet, size); + socket_connection_send_packet(btstack_connection, HCI_ACL_DATA_PACKET, hci_cmd_buffer, size); return 0; } diff --git a/src/daemon.c b/src/daemon.c index 2fc899df4..d36b47964 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -94,7 +94,7 @@ int main (int argc, const char * argv[]){ // @TODO make port and/or socket configurable per config.h // create server - socket_connection_create_tcp(1919); + socket_connection_create_tcp(BTSTACK_PORT); socket_connection_register_packet_callback(daemon_packet_handler); // go! diff --git a/src/socket_connection.c b/src/socket_connection.c index b38ead594..cd6aaee30 100644 --- a/src/socket_connection.c +++ b/src/socket_connection.c @@ -9,22 +9,27 @@ #include "socket_connection.h" +#include "hci.h" + +#include #include #include -#include +#include #include -#include -#include #include -#include -#include +#include #include - -#include "hci.h" +#include #define MAX_PENDING_CONNECTIONS 10 #define DATA_BUF_SIZE 80 +/** prototypes */ +static int socket_connection_hci_process(struct data_source *ds, int ready); +static int socket_connection_dummy_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length); + +/** globals */ + /** packet header used over socket connections, in front of the HCI packet */ typedef struct packet_header { uint16_t length; @@ -51,9 +56,10 @@ static linked_list_t connections = NULL; /** client packet handler */ -static int socket_connection_dummy_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length); + static int (*socket_connection_packet_callback)(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length) = socket_connection_dummy_handler; + static int socket_connection_dummy_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length){ return 0; } @@ -80,20 +86,48 @@ void socket_connection_free_connection(connection_t *conn){ free(conn); } +void socket_connection_init_statemachine(connection_t *connection){ + // wait for next packet + connection->state = SOCKET_W4_HEADER; + connection->bytes_read = 0; + connection->bytes_to_read = sizeof(packet_header_t); +} + +connection_t * socket_connection_register_new_connection(int fd){ + // create connection objec + connection_t * conn = malloc( sizeof(connection_t)); + if (conn == NULL) return 0; + linked_item_set_user( &conn->ds.item, conn); + linked_item_set_user( &conn->item, conn); + conn->ds.fd = fd; + conn->ds.process = socket_connection_hci_process; + + // prepare state machine and + socket_connection_init_statemachine(conn); + + // add this socket to the run_loop + run_loop_add( &conn->ds ); + + // and the connection list + linked_list_add( &connections, &conn->item); + + return conn; +} + int socket_connection_hci_process(struct data_source *ds, int ready) { connection_t *conn = (connection_t *) ds; int bytes_read = read(ds->fd, &conn->buffer[conn->bytes_read], conn->bytes_to_read); - printf("socket_connection_connection_process: state %u, new %u, read %u, toRead %u\n", conn->state, - bytes_read, conn->bytes_read, conn->bytes_to_read); + // printf("socket_connection_connection_process: state %u, new %u, read %u, toRead %u\n", conn->state, + // bytes_read, conn->bytes_read, conn->bytes_to_read); if (bytes_read <= 0){ // free - socket_connection_free_connection( linked_item_get_user(&ds->item)); + socket_connection_free_connection(linked_item_get_user(&ds->item)); return 0; } conn->bytes_read += bytes_read; conn->bytes_to_read -= bytes_read; - hexdump( conn->buffer, conn->bytes_read); + // hexdump( conn->buffer, conn->bytes_read); if (conn->bytes_to_read > 0) { return 0; } @@ -106,50 +140,27 @@ int socket_connection_hci_process(struct data_source *ds, int ready) { // dispatch packet !!! (*socket_connection_packet_callback)(conn, conn->buffer[2], &conn->buffer[sizeof(packet_header_t)], READ_BT_16( conn->buffer, 0)); - - // wait for next packet - conn->state = SOCKET_W4_HEADER; - conn->bytes_read = 0; - conn->bytes_to_read = sizeof(packet_header_t); + // reset state machine + socket_connection_init_statemachine(conn); break; } return 0; } - - static int socket_connection_accept(struct data_source *socket_ds, int ready) { - // create data_source_t - connection_t * conn = malloc( sizeof(connection_t)); - if (conn == NULL) return 0; - conn->ds.fd = 0; - conn->ds.process = socket_connection_hci_process; - - // init state machine - conn->state = SOCKET_W4_HEADER; - conn->bytes_read = 0; - conn->bytes_to_read = sizeof(packet_header_t); - /* New connection coming in! */ - conn->ds.fd = accept(socket_ds->fd, NULL, NULL); - if (conn->ds.fd < 0) { + int fd = accept(socket_ds->fd, NULL, NULL); + if (fd < 0) { perror("accept"); - free(conn); return 0; } // non-blocking ? // socket_connection_set_non_blocking(ds->fd); - printf("socket_connection_accept new connection %u\n", conn->ds.fd); + printf("socket_connection_accept new connection %u\n", fd); - // add this socket to the run_loop - linked_item_set_user( &conn->ds.item, conn); - run_loop_add( &conn->ds ); - - // and the connection list - linked_item_set_user( &conn->item, conn); - linked_list_add( &connections, &conn->item); + socket_connection_register_new_connection(fd); return 0; } @@ -258,3 +269,44 @@ void socket_connection_send_event_all(uint8_t *packet, uint16_t size){ socket_connection_send_packet_all( HCI_EVENT_PACKET, packet, size); return; } + +/** + * create socket connection to BTdaemon + */ +connection_t * socket_connection_open_tcp(){ + // TCP + struct protoent* tcp = getprotobyname("tcp"); + + int btsocket = socket(PF_INET, SOCK_STREAM, tcp->p_proto); + if(btsocket == -1){ + return NULL; + } + // localhost + struct sockaddr_in btdaemon_address; + btdaemon_address.sin_family = AF_INET; + btdaemon_address.sin_port = htons(BTSTACK_PORT); + struct hostent* localhost = gethostbyname("localhost"); + if(!localhost){ + return NULL; + } + // connect + char* addr = localhost->h_addr_list[0]; + memcpy(&btdaemon_address.sin_addr.s_addr, addr, sizeof addr); + if(connect(btsocket, (struct sockaddr*)&btdaemon_address, sizeof btdaemon_address) == -1){ + return NULL; + } + + return socket_connection_register_new_connection(btsocket); +} + + +/** + * close socket connection to BTdaemon + */ +int socket_connection_close_tcp(connection_t * connection){ + if (!connection) return -1; + shutdown(connection->ds.fd, SHUT_RDWR); + run_loop_remove(&connection->ds); + free( connection ); + return 0; +} \ No newline at end of file diff --git a/src/socket_connection.h b/src/socket_connection.h index f893d0d0d..3b96e5ee9 100644 --- a/src/socket_connection.h +++ b/src/socket_connection.h @@ -7,21 +7,35 @@ #pragma once #include "run_loop.h" + #include +/** TCP port for BTstack */ +#define BTSTACK_PORT 13333 + /** opaque connection type */ typedef struct connection connection_t; /** - * create socket data_source for tcp socket + * create socket for incoming tcp connections */ int socket_connection_create_tcp(int port); /** - * create socket data_source for unix domain socket + * create socket for incoming for unix domain connections */ int socket_connection_create_unix(char *path); +/** + * create socket connection to BTdaemon + */ +connection_t * socket_connection_open_tcp(); + +/** + * close socket connection to BTdaemon + */ +int socket_connection_close_tcp(connection_t *connection); + /** * set packet handler for all auto-accepted connections */