mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-11 09:40:24 +00:00
implemented run_loop compatible socket_server
This commit is contained in:
parent
bb96ef8cd9
commit
7596e361ff
12
TODO.txt
12
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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
142
src/socket_server.c
Normal 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
19
src/socket_server.h
Normal 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);
|
Loading…
x
Reference in New Issue
Block a user