diff options
author | Paul Kocialkowski <contact@paulk.fr> | 2012-11-05 22:06:31 +0100 |
---|---|---|
committer | Paul Kocialkowski <contact@paulk.fr> | 2012-11-05 22:06:31 +0100 |
commit | 3d58f7aba27b0a3eaa042c58801f4442d79a05e2 (patch) | |
tree | e727cbd722126afe612223e13abae3a7d85ae673 | |
parent | c54dc2a93836d387d17f57b7461cdd1d43550fcf (diff) | |
download | hardware_ril_samsung-ril-3d58f7aba27b0a3eaa042c58801f4442d79a05e2.zip hardware_ril_samsung-ril-3d58f7aba27b0a3eaa042c58801f4442d79a05e2.tar.gz hardware_ril_samsung-ril-3d58f7aba27b0a3eaa042c58801f4442d79a05e2.tar.bz2 |
SRS: Rework to handle multiple clients in a better way
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
-rw-r--r-- | samsung-ril.c | 4 | ||||
-rw-r--r-- | samsung-ril.h | 2 | ||||
-rw-r--r-- | srs.c | 528 | ||||
-rw-r--r-- | srs.h | 25 |
4 files changed, 436 insertions, 123 deletions
diff --git a/samsung-ril.c b/samsung-ril.c index 94ea564..36cdbb5 100644 --- a/samsung-ril.c +++ b/samsung-ril.c @@ -421,7 +421,7 @@ void ipc_rfs_dispatch(struct ipc_message_info *info) RIL_UNLOCK(); } -void srs_dispatch(int fd, struct srs_message *message) +void srs_dispatch(struct srs_message *message) { if(message == NULL) return; @@ -430,7 +430,7 @@ void srs_dispatch(int fd, struct srs_message *message) switch(message->command) { case SRS_CONTROL_PING: - srs_control_ping(fd, message); + srs_control_ping(message); break; case SRS_SND_SET_CALL_CLOCK_SYNC: srs_snd_set_call_clock_sync(message); diff --git a/samsung-ril.h b/samsung-ril.h index 4415727..862391c 100644 --- a/samsung-ril.h +++ b/samsung-ril.h @@ -199,7 +199,7 @@ extern struct ril_data ril_data; void ipc_fmt_dispatch(struct ipc_message_info *info); void ipc_rfs_dispatch(struct ipc_message_info *info); -void srs_dispatch(int fd, struct srs_message *message); +void srs_dispatch(struct srs_message *message); /* GEN */ @@ -18,6 +18,7 @@ * */ +#include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/socket.h> @@ -34,97 +35,336 @@ #include "samsung-ril.h" #include "util.h" -static int srs_server_send_message(int client_fd, struct srs_message *message) +int srs_client_register(struct srs_client_data *client_data, int fd) { - fd_set fds; + struct srs_client_info *client; + struct list_head *list_end; + struct list_head *list; + + if(client_data == NULL) + return -1; + + client = calloc(1, sizeof(struct srs_client_info)); + if(client == NULL) + return -1; + + client->fd = fd; + + list_end = client_data->clients; + while(list_end != NULL && list_end->next != NULL) + list_end = list_end->next; + + list = list_head_alloc((void *) client, list_end, NULL); + + if(client_data->clients == NULL) + client_data->clients = list; + + return 0; +} + +void srs_client_unregister(struct srs_client_data *client_data, struct srs_client_info *client) +{ + struct list_head *list; + + if(client_data == NULL || client == NULL) + return; + + list = client_data->clients; + while(list != NULL) { + if(list->data == (void *) client) { + memset(client, 0, sizeof(struct srs_client_info)); + free(client); + + if(list == client_data->clients) + client_data->clients = list->next; + + list_head_free(list); + + break; + } +list_continue: + list = list->next; + } +} + +struct srs_client_info *srs_client_info_find(struct srs_client_data *client_data) +{ + struct srs_client_info *client; + struct list_head *list; + + list = client_data->clients; + while(list != NULL) { + client = (struct srs_client_info *) list->data; + if(client == NULL) + goto list_continue; + + return client; + +list_continue: + list = list->next; + } + + return NULL; +} + +struct srs_client_info *srs_client_info_find_fd(struct srs_client_data *client_data, int fd) +{ + struct srs_client_info *client; + struct list_head *list; + + list = client_data->clients; + while(list != NULL) { + client = (struct srs_client_info *) list->data; + if(client == NULL) + goto list_continue; + + if(client->fd == fd) + return client; + +list_continue: + list = list->next; + } + + return NULL; +} +int srs_client_info_fill_fd_set(struct srs_client_data *client_data, fd_set *fds) +{ + struct srs_client_info *client; + struct list_head *list; + int fd_max; + + if(client_data == NULL || fds == NULL) + return -1; + + fd_max = -1; + list = client_data->clients; + while(list != NULL) { + client = (struct srs_client_info *) list->data; + if(client == NULL) + goto list_continue; + + FD_SET(client->fd, fds); + if(client->fd > fd_max) + fd_max = client->fd; + +list_continue: + list = list->next; + } + + return fd_max; +} + +int srs_client_info_get_fd_set(struct srs_client_data *client_data, fd_set *fds) +{ + struct srs_client_info *client; + struct list_head *list; + int fd; + + if(client_data == NULL || fds == NULL) + return -1; + + list = client_data->clients; + while(list != NULL) { + client = (struct srs_client_info *) list->data; + if(client == NULL) + goto list_continue; + + if(FD_ISSET(client->fd, fds)) { + FD_CLR(client->fd, fds); + return client->fd; + } + +list_continue: + list = list->next; + } + + return -1; +} + +int srs_client_send_message(struct srs_client_data *client_data, struct srs_message *message) +{ struct srs_header header; void *data; + struct timeval timeout; + fd_set fds; + int rc; + + if(client_data == NULL || message == NULL) + return -1; + + memset(&header, 0, sizeof(header)); header.length = message->data_len + sizeof(header); header.group = SRS_GROUP(message->command); header.index = SRS_INDEX(message->command); - data = malloc(header.length); - memset(data, 0, header.length); + data = calloc(1, header.length); + if(data == NULL) + return -1; memcpy(data, &header, sizeof(header)); - memcpy((void *) ((char*)data + sizeof(header)), - message->data, message->data_len); + memcpy((void *) ((char *) data + sizeof(header)), message->data, message->data_len); + + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 300; + + if(client_data->client_fd < 0) + goto error; FD_ZERO(&fds); - FD_SET(client_fd, &fds); + FD_SET(client_data->client_fd, &fds); - select(FD_SETSIZE, NULL, &fds, NULL, NULL); + rc = select(client_data->client_fd + 1, NULL, &fds, NULL, &timeout); - write(client_fd, data, header.length); + if(!FD_ISSET(client_data->client_fd, &fds)) { + LOGE("SRS write select failed on fd %d", client_data->client_fd); + goto error; + } + + rc = write(client_data->client_fd, data, header.length); + if(rc < (int) sizeof(struct srs_header)) { + LOGE("SRS write failed on fd %d with %d bytes", client_data->client_fd, rc); + goto error; + } free(data); + return rc; +error: + free(data); return 0; } -static int srs_server_send(int fd, unsigned short command, void *data, - int data_len) +int srs_client_send(struct srs_client_data *client_data, unsigned short command, void *data, int length) { + struct srs_client_info *client; struct srs_message message; int rc; + if(client_data == NULL) + return -1; + + memset(&message, 0, sizeof(message)); message.command = command; message.data = data; - message.data_len = data_len; + message.data_len = length; + + RIL_CLIENT_LOCK(client_data->client); + rc = srs_client_send_message(client_data, &message); + RIL_CLIENT_UNLOCK(client_data->client); - rc = srs_server_send_message(fd, &message); + if(rc <= 0) { + LOGD("SRS client with fd %d terminated", client_data->client_fd); + + client = srs_client_info_find_fd(client_data, client_data->client_fd); + if(client != NULL) + srs_client_unregister(client_data, client); + close(client_data->client_fd); + client_data->client_fd = -1; + } return rc; } -static int srs_server_recv(int client_fd, struct srs_message *message) +int srs_send(unsigned short command, void *data, int length) +{ + struct srs_client_data *client_data; + int rc; + + if(ril_data.srs_client == NULL || ril_data.srs_client->data == NULL) + return -1; + + client_data = (struct srs_client_data *) ril_data.srs_client->data; + + LOGD("SEND SRS: fd=%d command=%d data_len=%d", client_data->client_fd, command, length); + if(data != NULL && length > 0) { + LOGD("==== SRS DATA DUMP ===="); + hex_dump(data, length); + LOGD("======================="); + } + + return srs_client_send(client_data, command, data, length); +} + +int srs_client_recv(struct srs_client_data *client_data, struct srs_message *message) { - void *raw_data = malloc(SRS_DATA_MAX_SIZE); struct srs_header *header; + void *data; + + struct timeval timeout; + fd_set fds; int rc; - rc = read(client_fd, raw_data, SRS_DATA_MAX_SIZE); - if(rc < (int)sizeof(struct srs_header)) { + if(client_data == NULL || message == NULL) + return -1; + + data = calloc(1, SRS_DATA_MAX_SIZE); + if(data == NULL) return -1; + + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 300; + + if(client_data->client_fd < 0) + goto error; + + FD_ZERO(&fds); + FD_SET(client_data->client_fd, &fds); + + rc = select(client_data->client_fd + 1, &fds, NULL, NULL, &timeout); + + if(!FD_ISSET(client_data->client_fd, &fds)) { + LOGE("SRS read select failed on fd %d", client_data->client_fd); + goto error; + } + + rc = read(client_data->client_fd, data, SRS_DATA_MAX_SIZE); + if(rc < (int) sizeof(struct srs_header)) { + LOGE("SRS read failed on fd %d with %d bytes", client_data->client_fd, rc); + goto error; } - header = raw_data; + header = (struct srs_header *) data; + memset(message, 0, sizeof(struct srs_message)); message->command = SRS_COMMAND(header); message->data_len = header->length - sizeof(struct srs_header); - message->data = malloc(message->data_len); - - memcpy(message->data, (char*)raw_data + sizeof(struct srs_header), - message->data_len); + if(message->data_len > 0) { + message->data = calloc(1, message->data_len); + memcpy(message->data, (void *) ((char *) data + sizeof(struct srs_header)), message->data_len); + } else { + message->data = NULL; + } - free(raw_data); + free(data); + return rc; +error: + free(data); return 0; } -void srs_control_ping(int fd, struct srs_message *message) +void srs_control_ping(struct srs_message *message) { int caffe; - if(message->data == NULL) + if(message == NULL || message->data == NULL || message->data_len < (int) sizeof(int)) return; caffe=*((int *) message->data); if(caffe == SRS_CONTROL_CAFFE) { - srs_server_send(fd, SRS_CONTROL_PING, &caffe, sizeof(caffe)); + srs_send(SRS_CONTROL_PING, &caffe, sizeof(caffe)); } } static int srs_server_open(void) { - int server_fd = -1; + int server_fd; + int t; - int t = 0; - - while(t < 5) { + for(t=0 ; t < 5 ; t++) { unlink(SRS_SOCKET_NAME); #if RIL_VERSION >= 6 server_fd = socket_local_server(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); @@ -132,154 +372,204 @@ static int srs_server_open(void) server_fd = socket_local_server(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); #endif if(server_fd >= 0) - break; - - t++; + return server_fd; } - return server_fd; + return -1; } -static void* srs_process_client(void *pfd) +void *srs_client_read_loop(void *data) { - struct srs_message srs_message; + struct srs_client_info *client; + struct srs_client_data *client_data; + struct srs_message message; + struct timeval timeout; fd_set fds; - int client_fd = -1; - if (!pfd) { - LOGE("SRS client data is NULL"); - goto fail; - } + int fd_max; + int fd; + int rc; - client_fd = ((int*)pfd)[0]; + if(data == NULL) + pthread_exit(NULL); - while (1) { - if (client_fd < 0) - break; + client_data = (struct srs_client_data *) data; + while(client_data->running) { FD_ZERO(&fds); - FD_SET(client_fd, &fds); - select(FD_SETSIZE, &fds, NULL, NULL, NULL); + SRS_CLIENT_LOCK(); + fd_max = srs_client_info_fill_fd_set(client_data, &fds); + SRS_CLIENT_UNLOCK(); + + if(fd_max < 0) { + usleep(3000); + continue; + } + + timeout.tv_sec = 0; + timeout.tv_usec = 3000; + + select(fd_max + 1, &fds, NULL, NULL, &timeout); + + SRS_CLIENT_LOCK(); + while((fd = srs_client_info_get_fd_set(client_data, &fds)) >= 0) { + client_data->client_fd = fd; + + RIL_CLIENT_LOCK(client_data->client); + rc = srs_client_recv(client_data, &message); + if(rc <= 0) { + LOGD("SRS client with fd %d terminated", fd); - if (FD_ISSET(client_fd, &fds)) { - if (srs_server_recv(client_fd, &srs_message) < 0) { - LOGE("SRS recv failed, aborting!"); - break; + client = srs_client_info_find_fd(client_data, fd); + if(client != NULL) + srs_client_unregister(client_data, client); + close(fd); + + RIL_CLIENT_UNLOCK(client_data->client); + continue; } + RIL_CLIENT_UNLOCK(client_data->client); - LOGD("SRS recv: command=%d data_len=%d", - srs_message.command, srs_message.data_len); - hex_dump(srs_message.data, srs_message.data_len); + LOGD("RECV SRS: fd=%d command=%d data_len=%d", fd, message.command, message.data_len); + if(message.data != NULL && message.data_len > 0) { + LOGD("==== SRS DATA DUMP ===="); + hex_dump(message.data, message.data_len); + LOGD("======================="); + } - srs_dispatch(client_fd, &srs_message); + srs_dispatch(&message); - if (srs_message.data != NULL) - free(srs_message.data); - } - } + if(message.data != NULL) + free(message.data); -fail: - if(client_fd >= 0) { - close(client_fd); + client_data->client_fd = -1; + } + SRS_CLIENT_UNLOCK(); } - LOGE("SRS server client ended!"); + pthread_exit(NULL); return NULL; } -static int srs_read_loop(struct ril_client *client) +int srs_read_loop(struct ril_client *client) { - int rc; - + struct srs_client_data *client_data; struct sockaddr_un client_addr; int client_addr_len; + pthread_attr_t attr; + int fd; + int rc; - if(client == NULL) { - LOGE("client is NULL, aborting!"); + if(client == NULL || client->data == NULL) return -1; - } - if(client->data == NULL) { - LOGE("client data is NULL, aborting!"); - return -1; - } + client_data = (struct srs_client_data *) client->data; - int server_fd = ((int*)client->data)[0]; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - while(1) { - if(server_fd < 0) { - LOGE("SRS client server_fd is negative, aborting!"); - return -1; - } + client_data->running = 1; + + rc = pthread_create(&client_data->thread, &attr, srs_client_read_loop, (void *) client_data); + if(rc < 0) { + LOGE("Unable to create SRS client read loop thread"); + return -1; + } - rc = accept(server_fd, (struct sockaddr*)&client_addr, + while(client_data->server_fd >= 0) { + fd = accept(client_data->server_fd, (struct sockaddr *) &client_addr, &client_addr_len); - if (rc < 0) { - LOGE("SRS Failed to accept errno %d error %s", - errno, strerror(errno)); - return -1; - } - LOGI("SRS accepted fd %d", rc); - int *pfd = (int*)malloc(sizeof(int)); - if (!pfd) { - LOGE("out of memory for the client socket"); - close(rc); - return -1; + if(fd < 0) { + LOGE("Unable to accept new SRS client"); + break; } - *pfd = rc; - - pthread_t t; - if (pthread_create(&t, NULL, srs_process_client, pfd)) { - LOGE("SRS failed to start client thread errno %d error %s", - errno, strerror(errno)); - close(rc); - return -1; + + fcntl(fd, F_SETFL, O_NONBLOCK); + + LOGD("Accepted new SRS client from fd %d", fd); + + SRS_CLIENT_LOCK(); + rc = srs_client_register(client_data, fd); + SRS_CLIENT_UNLOCK(); + if(rc < 0) { + LOGE("Unable to register SRS client"); + break; } } + LOGE("SRS server failure"); + + client_data->running = 0; + + // Wait for the thread to finish + pthread_join(client_data->thread, NULL); + return 0; } -static int srs_create(struct ril_client *client) +int srs_create(struct ril_client *client) { - int *srs_server = NULL; + struct srs_client_data *client_data = NULL; + + if(client == NULL) + return -1; LOGD("Creating new SRS client"); - srs_server = malloc(sizeof(int)); - if (!srs_server) { - LOGE("SRS out of memory for server fd"); - goto fail; + signal(SIGPIPE, SIG_IGN); + + client_data = (struct srs_client_data *) calloc(1, sizeof(struct srs_client_data)); + if(client_data == NULL) { + LOGE("SRS client data creation failed"); + return -1; } - client->data = (void *) srs_server; - if((*srs_server = srs_server_open()) < 0) { - LOGE("%s: samsung-ril-socket server open failed", __FUNCTION__); + client_data->server_fd = srs_server_open(); + if(client_data->server_fd < 0) { + LOGE("SRS server creation failed"); goto fail; } + pthread_mutex_init(&client_data->mutex, NULL); + + client_data->client = client; + client->data = (void *) client_data; + return 0; fail: - if (srs_server) { - free(srs_server); - } + if(client_data != NULL) + free(client_data); + return -1; } -static int srs_destroy(struct ril_client *client) +int srs_destroy(struct ril_client *client) { - if (!client) { - return 0; - } + struct srs_client_data *client_data = NULL; + struct srs_client_info *client_info; - int *srs_server = (int*) client->data; - if (!srs_server) { + if(client == NULL) return 0; + + if(client->data == NULL) + return -1; + + client_data = (struct srs_client_data *) client->data; + + pthread_mutex_destroy(&client_data->mutex); + + while((client_info = srs_client_info_find(client_data)) != NULL) { + close(client_info->fd); + srs_client_unregister(client_data, client_info); } - close(*srs_server); - free(srs_server); + if(client_data->server_fd > 0) + close(client_data->server_fd); + + memset(client_data, 0, sizeof(struct srs_client_data)); + free(client_data); + client->data = NULL; return 0; } @@ -23,6 +23,7 @@ #include <sys/types.h> #include <sys/socket.h> +#include <sys/select.h> #include <sys/un.h> #include <arpa/inet.h> @@ -30,7 +31,29 @@ #include <samsung-ril-socket.h> +#define SRS_CLIENT_LOCK() pthread_mutex_lock(&client_data->mutex) +#define SRS_CLIENT_UNLOCK() pthread_mutex_unlock(&client_data->mutex) + +struct srs_client_info { + int fd; +}; + +struct srs_client_data { + struct ril_client *client; + + int server_fd; + int client_fd; + + struct list_head *clients; + + pthread_t thread; + pthread_mutex_t mutex; + int running; +}; + extern struct ril_client_funcs srs_client_funcs; -extern void srs_control_ping(int fd, struct srs_message *message); + +int srs_send(unsigned short command, void *data, int length); +void srs_control_ping(struct srs_message *message); #endif |