From 7596e361ff0adaa86c15b2b719c420464539c73c Mon Sep 17 00:00:00 2001 From: "matthias.ringwald" Date: Sat, 6 Jun 2009 21:10:20 +0000 Subject: [PATCH] implemented run_loop compatible socket_server --- TODO.txt | 12 +-- project.xcodeproj/project.pbxproj | 6 ++ src/hci_transport_h4.c | 4 +- src/main.c | 7 +- src/run_loop.c | 8 +- src/socket_server.c | 142 ++++++++++++++++++++++++++++++ src/socket_server.h | 19 ++++ 7 files changed, 183 insertions(+), 15 deletions(-) create mode 100644 src/socket_server.c create mode 100644 src/socket_server.h diff --git a/TODO.txt b/TODO.txt index 71a2c22bd..d6fe5182a 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,16 +1,8 @@ /* new todo file for BTstack */ -NEW FUNCTIONALITY -- implement single connection event-driven socket server - - socket fd in data_source can be temp. replaced by actual connection fd - IMPROVE - make data_source_t opaque: data_source_set_fd, data_source_set_cb - implement TimerSource - implement some kind of noitfy mechanism between multiple units -- make SocketServer object-oriented - - put data into struct - - DataSource * dataSource = SocketServer_createUnixSocket( name ); - - DataSource * dataSource = SocketServer_createTcpSocket( port); - - how to handle multiple parallel connections? - - callback to announce new connection, allow to store local context pointer +- support better handling of multiple parallel socket connections? + - callback to announce new connection, allow to store local context pointer diff --git a/project.xcodeproj/project.pbxproj b/project.xcodeproj/project.pbxproj index 9bd39295b..1709cdb0d 100644 --- a/project.xcodeproj/project.pbxproj +++ b/project.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 9C1F0E9A0FDAE023008F472F /* run_loop.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C1F0E980FDAE023008F472F /* run_loop.c */; }; + 9C1F0F340FDB024B008F472F /* socket_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C1F0F320FDB024B008F472F /* socket_server.c */; }; 9C46FBAF0FA8F31800ABEF05 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C46FBAE0FA8F31800ABEF05 /* main.c */; }; 9C46FC390FA906F700ABEF05 /* hci.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C46FC340FA906F700ABEF05 /* hci.c */; }; 9C46FC3A0FA906F700ABEF05 /* hci_transport_h4.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C46FC360FA906F700ABEF05 /* hci_transport_h4.c */; }; @@ -32,6 +33,8 @@ 8DD76FB20486AB0100D96B5E /* project */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = project; sourceTree = BUILT_PRODUCTS_DIR; }; 9C1F0E980FDAE023008F472F /* run_loop.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = run_loop.c; path = src/run_loop.c; sourceTree = ""; }; 9C1F0E990FDAE023008F472F /* run_loop.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = run_loop.h; path = src/run_loop.h; sourceTree = ""; }; + 9C1F0F320FDB024B008F472F /* socket_server.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = socket_server.c; path = src/socket_server.c; sourceTree = ""; }; + 9C1F0F330FDB024B008F472F /* socket_server.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = socket_server.h; path = src/socket_server.h; sourceTree = ""; }; 9C46FBAE0FA8F31800ABEF05 /* main.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = ""; usesTabs = 0; }; 9C46FC340FA906F700ABEF05 /* hci.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci.c; path = src/hci.c; sourceTree = ""; }; 9C46FC350FA906F700ABEF05 /* hci.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = hci.h; path = src/hci.h; sourceTree = ""; }; @@ -88,6 +91,8 @@ 9C7ECBB40FCC95DD0085DAC5 /* hci_dump.c */, 9C1F0E990FDAE023008F472F /* run_loop.h */, 9C1F0E980FDAE023008F472F /* run_loop.c */, + 9C1F0F320FDB024B008F472F /* socket_server.c */, + 9C1F0F330FDB024B008F472F /* socket_server.h */, ); name = Source; sourceTree = ""; @@ -158,6 +163,7 @@ 9C7ECB840FCC85650085DAC5 /* bt_control_iphone.c in Sources */, 9C7ECBB50FCC95DD0085DAC5 /* hci_dump.c in Sources */, 9C1F0E9A0FDAE023008F472F /* run_loop.c in Sources */, + 9C1F0F340FDB024B008F472F /* socket_server.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/hci_transport_h4.c b/src/hci_transport_h4.c index 99adb4943..9e1e08ee3 100644 --- a/src/hci_transport_h4.c +++ b/src/hci_transport_h4.c @@ -171,7 +171,7 @@ static void h4_register_acl_packet_handler (void (*handler)(uint8_t *packet, acl_packet_handler = handler; } -static int h4_handle_data() { +static int h4_process(struct data_source *ds, int ready) { if (hci_transport_h4->ds.fd == 0) return -1; // read up to bytes_to_read data in @@ -246,7 +246,7 @@ hci_transport_t * hci_transport_h4_instance() { if (hci_transport_h4 == NULL) { hci_transport_h4 = malloc( sizeof(hci_transport_t)); hci_transport_h4->ds.fd = 0; - hci_transport_h4->ds.process = h4_handle_data; + hci_transport_h4->ds.process = h4_process; hci_transport_h4->open = h4_open; hci_transport_h4->close = h4_close; hci_transport_h4->send_cmd_packet = h4_send_cmd_packet; diff --git a/src/main.c b/src/main.c index 680a98988..84a8a0392 100644 --- a/src/main.c +++ b/src/main.c @@ -18,6 +18,7 @@ #include "l2cap.h" #include "run_loop.h" +#include "socket_server.h" static hci_transport_t * transport; static hci_uart_config_t config; @@ -28,7 +29,7 @@ uint16_t dest_cid; void event_handler(uint8_t *packet, int size){ // printf("Event type: %x, opcode: %x, other %x\n", packet[0], packet[3] | packet[4] << 8); -#if 1 +#if 0 bd_addr_t addr = {0x00, 0x03, 0xc9, 0x3d, 0x77, 0x43 }; // Think Outside Keyboard // bd_addr_t addr = { 0x00, 0x16, 0xcb, 0x09, 0x94, 0xa9}; // MacBook Pro @@ -157,8 +158,12 @@ int main (int argc, const char * argv[]) { // trigger first hci action hci_run(); + // create server + data_source_t *socket_server = socket_server_create_tcp(1919); + // configure run loop run_loop_add( (data_source_t *) transport); + run_loop_add( socket_server ); // go! run_loop_execute(); diff --git a/src/run_loop.c b/src/run_loop.c index 544b1498e..139106f76 100644 --- a/src/run_loop.c +++ b/src/run_loop.c @@ -65,8 +65,12 @@ void run_loop_execute() { select( highest_fd+1 , &descriptors, NULL, NULL, NULL); // process input - for (ds = the_run_loop; ds != NULL ; ds = ds->next){ - ds->process(ds, FD_ISSET(ds->fd, &descriptors)); + data_source_t *next; + for (ds = the_run_loop; ds != NULL ; ds = next){ + next = ds->next; // cache pointer to next data_source to allow data source to remove itself + if (FD_ISSET(ds->fd, &descriptors)) { + ds->process(ds, FD_ISSET(ds->fd, &descriptors)); + } } } } diff --git a/src/socket_server.c b/src/socket_server.c new file mode 100644 index 000000000..12070f163 --- /dev/null +++ b/src/socket_server.c @@ -0,0 +1,142 @@ +/* + * SocketServer.c + * + * Handles multiple connections to a single socket without blocking + * + * Created by Matthias Ringwald on 6/6/09. + * + */ + +#include "socket_server.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PENDING_CONNECTIONS 10 +#define DATA_BUF_SIZE 80 + +static char test_buffer[DATA_BUF_SIZE]; + + +int socket_server_set_non_blocking(int fd) +{ + int err; + int flags; + // According to the man page, F_GETFL can't error! + flags = fcntl(fd, F_GETFL, NULL); + err = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + return err; +} + +static int socket_server_process(struct data_source *ds, int ready) { + int bytes_read = read(ds->fd, test_buffer, DATA_BUF_SIZE); + + // connection closed by client? + if (bytes_read < 0){ + + // emit signal + + // remove from run_loop + // @note: run_loop_execute must be prepared for this + run_loop_remove(ds); + + // destroy + free(ds); + + return 0; + } + + write(ds->fd, "echo: ", 5); + write(ds->fd, test_buffer, bytes_read); + + return 0; +} + + +static int socket_server_accept(struct data_source *socket_ds, int ready) { + + // create data_source_t + data_source_t *ds = malloc( sizeof(data_source_t)); + if (ds == NULL) return 0; + ds->fd = 0; + ds->process = socket_server_process; + + /* We have a new connection coming in! We'll + try to find a spot for it in connectlist. */ + ds->fd = accept(socket_ds->fd, NULL, NULL); + if (ds->fd < 0) { + perror("accept"); + free(ds); + return 0; + } + // non-blocking ? + // socket_server_set_non_blocking(ds->fd); + + // add this socket to the run_loop + run_loop_add( ds ); + + return 0; +} + +/** + * create socket data_source for tcp socket + * + * @return data_source object. If null, check errno + */ +data_source_t * socket_server_create_tcp(int port){ + + // create data_source_t + data_source_t *ds = malloc( sizeof(data_source_t)); + if (ds == NULL) return ds; + ds->fd = 0; + ds->process = socket_server_accept; + + // create tcp socket + struct sockaddr_in addr; + if ((ds->fd = socket (PF_INET, SOCK_STREAM, 0)) < 0) { + printf ("Error creating socket ...(%s)\n", strerror(errno)); + free(ds); + return NULL; + } + + printf ("Socket created\n"); + + addr.sin_family = AF_INET; + addr.sin_port = htons (port); + memset (&addr.sin_addr, 0, sizeof (addr.sin_addr)); + + const int y = 1; + setsockopt(ds->fd, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(int)); + + if (bind ( ds->fd, (struct sockaddr *) &addr, sizeof (addr) ) ) { + printf ("Error on bind() ...(%s)\n", strerror(errno)); + free(ds); + return NULL; + } + + if (listen (ds->fd, MAX_PENDING_CONNECTIONS)) { + printf ("Error on listen() ...(%s)\n", strerror(errno)); + free(ds); + return NULL; + } + + printf ("Server up and running ...\n"); + return ds; +} + +/** + * create socket data_source for unix domain socket + * + * @TODO: implement socket_server_create_unix + */ +data_source_t * socket_server_create_unix(char *path){ + return 0; +} + diff --git a/src/socket_server.h b/src/socket_server.h new file mode 100644 index 000000000..a7c8ccc13 --- /dev/null +++ b/src/socket_server.h @@ -0,0 +1,19 @@ +/* + * socket_server.h + * + * Created by Matthias Ringwald on 6/6/09. + */ + +#pragma once + +#include "run_loop.h" + +/** + * create socket data_source for tcp socket + */ +data_source_t * socket_server_create_tcp(int port); + +/** + * create socket data_source for unix domain socket + */ +data_source_t * socket_server_create_unix(char *path); \ No newline at end of file