implemented run_loop compatible socket_server

This commit is contained in:
matthias.ringwald 2009-06-06 21:10:20 +00:00
parent bb96ef8cd9
commit 7596e361ff
7 changed files with 183 additions and 15 deletions

View File

@ -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

View File

@ -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 = "<group>"; };
9C1F0E990FDAE023008F472F /* run_loop.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = run_loop.h; path = src/run_loop.h; sourceTree = "<group>"; };
9C1F0F320FDB024B008F472F /* socket_server.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = socket_server.c; path = src/socket_server.c; sourceTree = "<group>"; };
9C1F0F330FDB024B008F472F /* socket_server.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = socket_server.h; path = src/socket_server.h; sourceTree = "<group>"; };
9C46FBAE0FA8F31800ABEF05 /* main.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = "<group>"; usesTabs = 0; };
9C46FC340FA906F700ABEF05 /* hci.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci.c; path = src/hci.c; sourceTree = "<group>"; };
9C46FC350FA906F700ABEF05 /* hci.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = hci.h; path = src/hci.h; sourceTree = "<group>"; };
@ -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 = "<group>";
@ -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;
};

View File

@ -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;

View File

@ -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();

View File

@ -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));
}
}
}
}

142
src/socket_server.c Normal file
View File

@ -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 <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/socket.h>
#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;
}

19
src/socket_server.h Normal file
View File

@ -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);