mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-29 04:20:20 +00:00
prepare socket_server to be used by both client and server
This commit is contained in:
parent
e7284470b7
commit
59cc82e457
14
src/daemon.c
14
src/daemon.c
@ -37,6 +37,18 @@
|
|||||||
static hci_transport_t * transport;
|
static hci_transport_t * transport;
|
||||||
static hci_uart_config_t config;
|
static hci_uart_config_t config;
|
||||||
|
|
||||||
|
static int daemon_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length){
|
||||||
|
switch (packet_type){
|
||||||
|
case HCI_COMMAND_DATA_PACKET:
|
||||||
|
hci_send_cmd_packet(data, length);
|
||||||
|
break;
|
||||||
|
case HCI_ACL_DATA_PACKET:
|
||||||
|
hci_send_acl_packet(data, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main (int argc, const char * argv[]){
|
int main (int argc, const char * argv[]){
|
||||||
|
|
||||||
bt_control_t * control = NULL;
|
bt_control_t * control = NULL;
|
||||||
@ -83,7 +95,7 @@ int main (int argc, const char * argv[]){
|
|||||||
|
|
||||||
// create server
|
// create server
|
||||||
socket_server_create_tcp(1919);
|
socket_server_create_tcp(1919);
|
||||||
socket_server_register_process_callback(socket_server_connection_process);
|
socket_server_register_packet_callback(daemon_packet_handler);
|
||||||
|
|
||||||
// go!
|
// go!
|
||||||
run_loop_execute();
|
run_loop_execute();
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#define MAX_PENDING_CONNECTIONS 10
|
#define MAX_PENDING_CONNECTIONS 10
|
||||||
#define DATA_BUF_SIZE 80
|
#define DATA_BUF_SIZE 80
|
||||||
|
|
||||||
|
/** packet header used over socket connections, in front of the HCI packet */
|
||||||
typedef struct packet_header {
|
typedef struct packet_header {
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
@ -37,21 +37,27 @@ typedef enum {
|
|||||||
SOCKET_W4_DATA,
|
SOCKET_W4_DATA,
|
||||||
} SOCKET_STATE;
|
} SOCKET_STATE;
|
||||||
|
|
||||||
typedef struct connection {
|
struct connection {
|
||||||
data_source_t ds; // used for run loop
|
data_source_t ds; // used for run loop
|
||||||
linked_item_t item; // used for connection list
|
linked_item_t item; // used for connection list
|
||||||
SOCKET_STATE state;
|
SOCKET_STATE state;
|
||||||
uint16_t bytes_read;
|
uint16_t bytes_read;
|
||||||
uint16_t bytes_to_read;
|
uint16_t bytes_to_read;
|
||||||
uint8_t buffer[3+3+255]; // max HCI CMD + packet_header
|
uint8_t buffer[3+3+255]; // max HCI CMD + packet_header
|
||||||
} connection_t;
|
};
|
||||||
|
|
||||||
linked_list_t connections = NULL;
|
/** list of socket connections */
|
||||||
|
static linked_list_t connections = NULL;
|
||||||
|
|
||||||
static char test_buffer[DATA_BUF_SIZE];
|
|
||||||
|
|
||||||
static int socket_server_echo_process(struct data_source *ds, int ready);
|
/** client packet handler */
|
||||||
static int (*socket_server_process)(struct data_source *ds, int ready) = socket_server_echo_process;
|
static int socket_server_dummy_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length);
|
||||||
|
static int (*socket_server_packet_callback)(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length) = socket_server_dummy_handler;
|
||||||
|
|
||||||
|
static int socket_server_dummy_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int socket_server_set_non_blocking(int fd)
|
int socket_server_set_non_blocking(int fd)
|
||||||
{
|
{
|
||||||
@ -74,23 +80,7 @@ void socket_server_free_connection(connection_t *conn){
|
|||||||
free(conn);
|
free(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int socket_server_echo_process(struct data_source *ds, int ready) {
|
int socket_server_hci_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){
|
|
||||||
// free
|
|
||||||
socket_server_free_connection( linked_item_get_user(&ds->item));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
write(ds->fd, "echo: ", 5);
|
|
||||||
write(ds->fd, test_buffer, bytes_read);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int socket_server_connection_process(struct data_source *ds, int ready) {
|
|
||||||
connection_t *conn = (connection_t *) ds;
|
connection_t *conn = (connection_t *) ds;
|
||||||
int bytes_read = read(ds->fd, &conn->buffer[conn->bytes_read], conn->bytes_to_read);
|
int bytes_read = read(ds->fd, &conn->buffer[conn->bytes_read], conn->bytes_to_read);
|
||||||
|
|
||||||
@ -113,17 +103,9 @@ int socket_server_connection_process(struct data_source *ds, int ready) {
|
|||||||
conn->bytes_to_read = READ_BT_16( conn->buffer, 0);
|
conn->bytes_to_read = READ_BT_16( conn->buffer, 0);
|
||||||
break;
|
break;
|
||||||
case SOCKET_W4_DATA:
|
case SOCKET_W4_DATA:
|
||||||
// process packet !!!
|
// dispatch packet !!!
|
||||||
switch (conn->buffer[2]){
|
(*socket_server_packet_callback)(conn, conn->buffer[2], &conn->buffer[sizeof(packet_header_t)],
|
||||||
case HCI_COMMAND_DATA_PACKET:
|
READ_BT_16( conn->buffer, 0));
|
||||||
hci_send_cmd_packet(&conn->buffer[sizeof(packet_header_t)], READ_BT_16( conn->buffer, 0));
|
|
||||||
break;
|
|
||||||
case HCI_ACL_DATA_PACKET:
|
|
||||||
hci_send_acl_packet(&conn->buffer[sizeof(packet_header_t)], READ_BT_16( conn->buffer, 0));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for next packet
|
// wait for next packet
|
||||||
conn->state = SOCKET_W4_HEADER;
|
conn->state = SOCKET_W4_HEADER;
|
||||||
@ -134,31 +116,6 @@ int socket_server_connection_process(struct data_source *ds, int ready) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_server_send_packet_all(uint8_t type, uint8_t *packet, uint16_t size){
|
|
||||||
uint8_t length[2];
|
|
||||||
bt_store_16( (uint8_t *) &length, 0, size);
|
|
||||||
linked_item_t *next;
|
|
||||||
linked_item_t *it;
|
|
||||||
for (it = (linked_item_t *) connections; it != NULL ; it = next){
|
|
||||||
next = it->next; // cache pointer to next connection_t to allow for removal
|
|
||||||
connection_t *conn = (connection_t *) linked_item_get_user(it);
|
|
||||||
write(conn->ds.fd, &length, 2);
|
|
||||||
write(conn->ds.fd, &type, 1);
|
|
||||||
write(conn->ds.fd, &type, 1); // padding for now
|
|
||||||
write(conn->ds.fd, packet, size);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void socket_server_send_event_all(uint8_t *packet, uint16_t size){
|
|
||||||
socket_server_send_packet_all( HCI_EVENT_PACKET, packet, size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void socket_server_send_acl_all(uint8_t *packet, uint16_t size){
|
|
||||||
socket_server_send_packet_all( HCI_ACL_DATA_PACKET, packet, size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int socket_server_accept(struct data_source *socket_ds, int ready) {
|
static int socket_server_accept(struct data_source *socket_ds, int ready) {
|
||||||
@ -167,7 +124,7 @@ static int socket_server_accept(struct data_source *socket_ds, int ready) {
|
|||||||
connection_t * conn = malloc( sizeof(connection_t));
|
connection_t * conn = malloc( sizeof(connection_t));
|
||||||
if (conn == NULL) return 0;
|
if (conn == NULL) return 0;
|
||||||
conn->ds.fd = 0;
|
conn->ds.fd = 0;
|
||||||
conn->ds.process = socket_server_process;
|
conn->ds.process = socket_server_hci_process;
|
||||||
|
|
||||||
// init state machine
|
// init state machine
|
||||||
conn->state = SOCKET_W4_HEADER;
|
conn->state = SOCKET_W4_HEADER;
|
||||||
@ -202,11 +159,11 @@ static int socket_server_accept(struct data_source *socket_ds, int ready) {
|
|||||||
*
|
*
|
||||||
* @return data_source object. If null, check errno
|
* @return data_source object. If null, check errno
|
||||||
*/
|
*/
|
||||||
data_source_t * socket_server_create_tcp(int port){
|
int socket_server_create_tcp(int port){
|
||||||
|
|
||||||
// create data_source_t
|
// create data_source_t
|
||||||
data_source_t *ds = malloc( sizeof(data_source_t));
|
data_source_t *ds = malloc( sizeof(data_source_t));
|
||||||
if (ds == NULL) return NULL;
|
if (ds == NULL) return -1;
|
||||||
ds->fd = 0;
|
ds->fd = 0;
|
||||||
ds->process = socket_server_accept;
|
ds->process = socket_server_accept;
|
||||||
|
|
||||||
@ -214,7 +171,7 @@ data_source_t * socket_server_create_tcp(int port){
|
|||||||
if ((ds->fd = socket (PF_INET, SOCK_STREAM, 0)) < 0) {
|
if ((ds->fd = socket (PF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
printf ("Error creating socket ...(%s)\n", strerror(errno));
|
printf ("Error creating socket ...(%s)\n", strerror(errno));
|
||||||
free(ds);
|
free(ds);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf ("Socket created\n");
|
printf ("Socket created\n");
|
||||||
@ -230,19 +187,19 @@ data_source_t * socket_server_create_tcp(int port){
|
|||||||
if (bind ( ds->fd, (struct sockaddr *) &addr, sizeof (addr) ) ) {
|
if (bind ( ds->fd, (struct sockaddr *) &addr, sizeof (addr) ) ) {
|
||||||
printf ("Error on bind() ...(%s)\n", strerror(errno));
|
printf ("Error on bind() ...(%s)\n", strerror(errno));
|
||||||
free(ds);
|
free(ds);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen (ds->fd, MAX_PENDING_CONNECTIONS)) {
|
if (listen (ds->fd, MAX_PENDING_CONNECTIONS)) {
|
||||||
printf ("Error on listen() ...(%s)\n", strerror(errno));
|
printf ("Error on listen() ...(%s)\n", strerror(errno));
|
||||||
free(ds);
|
free(ds);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
run_loop_add(ds);
|
run_loop_add(ds);
|
||||||
|
|
||||||
printf ("Server up and running ...\n");
|
printf ("Server up and running ...\n");
|
||||||
return ds;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,14 +207,54 @@ data_source_t * socket_server_create_tcp(int port){
|
|||||||
*
|
*
|
||||||
* @TODO: implement socket_server_create_unix
|
* @TODO: implement socket_server_create_unix
|
||||||
*/
|
*/
|
||||||
data_source_t * socket_server_create_unix(char *path){
|
int socket_server_create_unix(char *path){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* register data available callback
|
* set packet handler for all auto-accepted connections
|
||||||
* @todo: hack callback to allow data reception - replace with better architecture
|
|
||||||
*/
|
*/
|
||||||
void socket_server_register_process_callback( int (*process_callback)(struct data_source *ds, int ready) ){
|
void socket_server_register_packet_callback( int (*packet_callback)(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length) ){
|
||||||
socket_server_process = process_callback;
|
socket_server_packet_callback = packet_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send HCI packet to single connection
|
||||||
|
*/
|
||||||
|
void socket_server_send_packet(connection_t *conn, uint8_t type, uint8_t *packet, uint16_t size){
|
||||||
|
uint8_t length[2];
|
||||||
|
bt_store_16( (uint8_t *) &length, 0, size);
|
||||||
|
|
||||||
|
write(conn->ds.fd, &length, 2);
|
||||||
|
write(conn->ds.fd, &type, 1);
|
||||||
|
write(conn->ds.fd, &type, 1); // padding for now
|
||||||
|
write(conn->ds.fd, packet, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send HCI packet to all connections
|
||||||
|
*/
|
||||||
|
int socket_server_send_packet_all(uint8_t type, uint8_t *packet, uint16_t size){
|
||||||
|
linked_item_t *next;
|
||||||
|
linked_item_t *it;
|
||||||
|
for (it = (linked_item_t *) connections; it != NULL ; it = next){
|
||||||
|
next = it->next; // cache pointer to next connection_t to allow for removal
|
||||||
|
socket_server_send_packet( (connection_t *) linked_item_get_user(it), type, packet, size);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send HCI ACL packet to all connections
|
||||||
|
*/
|
||||||
|
void socket_server_send_acl_all(uint8_t *packet, uint16_t size){
|
||||||
|
socket_server_send_packet_all( HCI_ACL_DATA_PACKET, packet, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* send HCI Event packet to all connections
|
||||||
|
*/
|
||||||
|
void socket_server_send_event_all(uint8_t *packet, uint16_t size){
|
||||||
|
socket_server_send_packet_all( HCI_EVENT_PACKET, packet, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@ -9,25 +9,31 @@
|
|||||||
#include "run_loop.h"
|
#include "run_loop.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** opaque connection type */
|
||||||
|
typedef struct connection connection_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create socket data_source for tcp socket
|
* create socket data_source for tcp socket
|
||||||
*/
|
*/
|
||||||
data_source_t * socket_server_create_tcp(int port);
|
int socket_server_create_tcp(int port);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create socket data_source for unix domain socket
|
* create socket data_source for unix domain socket
|
||||||
*/
|
*/
|
||||||
data_source_t * socket_server_create_unix(char *path);
|
int socket_server_create_unix(char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* register data available callback
|
* set packet handler for all auto-accepted connections
|
||||||
* @todo: hack callback to allow data reception - replace with better architecture
|
|
||||||
*/
|
*/
|
||||||
void socket_server_register_process_callback( int (*process_callback)(struct data_source *ds, int ready) );
|
void socket_server_register_packet_callback( int (*packet_callback)(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t length) );
|
||||||
int socket_server_connection_process(struct data_source *ds, int ready);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send HCI packet to single connection
|
||||||
|
*/
|
||||||
|
void socket_server_send_packet(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send event/acl data to all clients
|
||||||
|
*/
|
||||||
void socket_server_send_event_all(uint8_t *packet, uint16_t size);
|
void socket_server_send_event_all(uint8_t *packet, uint16_t size);
|
||||||
void socket_server_send_acl_all(uint8_t *packet, uint16_t size);
|
void socket_server_send_acl_all(uint8_t *packet, uint16_t size);
|
||||||
|
|
||||||
// send ACL packet
|
|
||||||
int hci_send_acl_packet(uint8_t *packet, int size);
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user