summaryrefslogtreecommitdiffstats
path: root/srs.c
diff options
context:
space:
mode:
authorPaul Kocialkowski <contact@paulk.fr>2012-11-05 22:06:31 +0100
committerPaul Kocialkowski <contact@paulk.fr>2012-11-05 22:06:31 +0100
commit3d58f7aba27b0a3eaa042c58801f4442d79a05e2 (patch)
treee727cbd722126afe612223e13abae3a7d85ae673 /srs.c
parentc54dc2a93836d387d17f57b7461cdd1d43550fcf (diff)
downloadhardware_replicant_libsamsung-ril-3d58f7aba27b0a3eaa042c58801f4442d79a05e2.tar.gz
hardware_replicant_libsamsung-ril-3d58f7aba27b0a3eaa042c58801f4442d79a05e2.tar.bz2
hardware_replicant_libsamsung-ril-3d58f7aba27b0a3eaa042c58801f4442d79a05e2.zip
SRS: Rework to handle multiple clients in a better way
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Diffstat (limited to 'srs.c')
-rw-r--r--srs.c528
1 files changed, 409 insertions, 119 deletions
diff --git a/srs.c b/srs.c
index 8683535..13f50a5 100644
--- a/srs.c
+++ b/srs.c
@@ -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;
}