summaryrefslogtreecommitdiffstats
path: root/srs-client
diff options
context:
space:
mode:
authorPaul Kocialkowski <contact@paulk.fr>2014-08-07 13:12:15 +0200
committerPaul Kocialkowski <contact@paulk.fr>2014-08-07 13:12:15 +0200
commita7ff1df1869ce543171a6ee92cbf821647b1bf7d (patch)
tree659e315b3d609f0f9e661d4de21b52077e6e2b81 /srs-client
parentc8408cd2c116b0b99a399282032b6607a1318b84 (diff)
downloadhardware_replicant_libsamsung-ril-a7ff1df1869ce543171a6ee92cbf821647b1bf7d.tar.gz
hardware_replicant_libsamsung-ril-a7ff1df1869ce543171a6ee92cbf821647b1bf7d.tar.bz2
hardware_replicant_libsamsung-ril-a7ff1df1869ce543171a6ee92cbf821647b1bf7d.zip
Samsung-RIL rewrite: harder, better, probably not faster but definitely stronger
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Diffstat (limited to 'srs-client')
-rw-r--r--srs-client/include/srs-client.h47
-rw-r--r--srs-client/srs-client.c551
2 files changed, 378 insertions, 220 deletions
diff --git a/srs-client/include/srs-client.h b/srs-client/include/srs-client.h
index 632e882..16eee49 100644
--- a/srs-client/include/srs-client.h
+++ b/srs-client/include/srs-client.h
@@ -1,7 +1,7 @@
/*
* This file is part of Samsung-RIL.
*
- * Copyright (C) 2013 Paul Kocialkowski <contact@oaulk.fr>
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
*
* Samsung-RIL is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,43 +17,46 @@
* along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <pthread.h>
-
-#include <samsung-ril-socket.h>
-
#ifndef _SRS_CLIENT_H_
#define _SRS_CLIENT_H_
-#define SRS_CLIENT_TIMEOUT 500000
+#include <stdlib.h>
+#include <pthread.h>
-#define SRS_CLIENT_LOCK(client) pthread_mutex_lock(&(client->mutex))
-#define SRS_CLIENT_UNLOCK(client) pthread_mutex_unlock(&(client->mutex))
+#include <samsung-ril-socket.h>
-typedef void (*srs_client_thread_cb)(struct srs_message *message);
+#define SRS_CLIENT_LOCK(client) pthread_mutex_lock(&client->mutex)
+#define SRS_CLIENT_UNLOCK(client) pthread_mutex_unlock(&client->mutex)
struct srs_client {
int fd;
+ int event_fd;
pthread_mutex_t mutex;
pthread_t thread;
- int thread_run;
- srs_client_thread_cb thread_cb;
+ void (*callback)(struct srs_client *client, struct srs_message *message);
};
-int srs_client_recv_message(struct srs_client *client, struct srs_message *message);
-int srs_client_send_message(struct srs_client *client, struct srs_message *message);
-int srs_client_send(struct srs_client *client, unsigned short command, void *data, int length);
+const char *srs_command_string(unsigned short command);
+int srs_header_setup(struct srs_header *header,
+ const struct srs_message *message);
+int srs_message_setup(const struct srs_header *header,
+ struct srs_message *message);
+int srs_ping(struct srs_client *client);
+
+struct srs_client *srs_client_create(void);
+int srs_client_destroy(struct srs_client *client);
int srs_client_open(struct srs_client *client);
int srs_client_close(struct srs_client *client);
-int srs_client_create(struct srs_client **client_p);
-int srs_client_destroy(struct srs_client *client);
-
-int srs_client_thread_start(struct srs_client *client,
- srs_client_thread_cb cb);
-int srs_client_thread_stop(struct srs_client *client);
-
-int srs_client_ping(struct srs_client *client);
+int srs_client_poll(struct srs_client *client);
+int srs_client_send(struct srs_client *client, unsigned short command,
+ void *data, size_t size);
+int srs_client_recv(struct srs_client *client, struct srs_message *message);
+int srs_client_loop(struct srs_client *client);
+int srs_client_loop_start(struct srs_client *client,
+ void (*callback)(struct srs_client *client, struct srs_message *message));
+int srs_client_loop_stop(struct srs_client *client);
#endif
diff --git a/srs-client/srs-client.c b/srs-client/srs-client.c
index 109b607..2e1c75d 100644
--- a/srs-client/srs-client.c
+++ b/srs-client/srs-client.c
@@ -1,7 +1,7 @@
/*
* This file is part of Samsung-RIL.
*
- * Copyright (C) 2013 Paul Kocialkowski <contact@oaulk.fr>
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
*
* Samsung-RIL is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
+#include <sys/eventfd.h>
#include <signal.h>
#include <arpa/inet.h>
@@ -39,120 +40,254 @@
#include <srs-client.h>
/*
- * SRS Client fops
+ * Utils
*/
-int srs_client_recv_message(struct srs_client *client, struct srs_message *message)
+const char *srs_command_string(unsigned short command)
{
- struct srs_header *header_p;
- struct srs_header header;
- void *data = NULL;
- int length = 0;
+ static char command_string[7] = { 0 };
+
+ switch (command) {
+ case SRS_CONTROL_PING:
+ return "SRS_CONTROL_PING";
+ case SRS_SND_SET_CALL_VOLUME:
+ return "SRS_SND_SET_CALL_VOLUME";
+ case SRS_SND_SET_CALL_AUDIO_PATH:
+ return "SRS_SND_SET_CALL_AUDIO_PATH";
+ case SRS_SND_SET_CALL_CLOCK_SYNC:
+ return "SRS_SND_SET_CALL_CLOCK_SYNC";
+ default:
+ snprintf((char *) &command_string, sizeof(command_string), "0x%04x", command);
+ return command_string;
+ }
+}
- struct timeval timeout;
- fd_set fds;
- int rc;
+int srs_header_setup(struct srs_header *header,
+ const struct srs_message *message)
+{
+ if (header == NULL || message == NULL)
+ return -1;
- if (client == NULL || message == NULL || client->fd < 0)
- return -EINVAL;
+ memset(header, 0, sizeof(struct srs_header));
+ header->length = message->size + sizeof(struct srs_header);
+ header->group = SRS_GROUP(message->command);
+ header->index = SRS_INDEX(message->command);
+
+ return 0;
+}
+
+int srs_message_setup(const struct srs_header *header,
+ struct srs_message *message)
+{
+ if (header == NULL || message == NULL)
+ return -1;
memset(message, 0, sizeof(struct srs_message));
- memset(&header, 0, sizeof(header));
+ message->command = SRS_COMMAND(header->group, header->index);
+ message->data = NULL;
+ message->size = 0;
- timeout.tv_sec = (SRS_CLIENT_TIMEOUT - SRS_CLIENT_TIMEOUT % 1000000) / 1000000;
- timeout.tv_usec = SRS_CLIENT_TIMEOUT % 1000000;
+ return 0;
+}
- FD_ZERO(&fds);
- FD_SET(client->fd, &fds);
+/*
+ * SRS
+ */
- rc = select(client->fd + 1, &fds, NULL, NULL, &timeout);
- if (rc == 0) {
- rc = 0;
- goto done;
- } else if (rc < 0 || !FD_ISSET(client->fd, &fds))
+int srs_ping(struct srs_client *client)
+{
+ struct srs_message message;
+ struct srs_control_ping_data ping;
+ struct srs_control_ping_data *pong;
+ int rc;
+
+ if (client == NULL)
+ return -1;
+
+ memset(&message, 0, sizeof(message));
+
+ memset(&ping, 0, sizeof(ping));
+ ping.caffe = SRS_CONTROL_CAFFE;
+
+ rc = srs_client_send(client, SRS_CONTROL_PING, &ping, sizeof(ping));
+ if (rc < 0)
goto error;
- SRS_CLIENT_LOCK(client);
- rc = read(client->fd, &header, sizeof(header));
- SRS_CLIENT_UNLOCK(client);
+ rc = srs_client_poll(client);
+ if (rc <= 0)
+ goto error;
- if (rc != sizeof(header))
+ rc = srs_client_recv(client, &message);
+ if (rc < 0 || message.data == NULL || message.size < sizeof(struct srs_control_ping_data))
goto error;
- header_p = &header;
- message->command = SRS_COMMAND(header_p);
+ pong = (struct srs_control_ping_data *) message.data;
+ if (pong->caffe != SRS_CONTROL_CAFFE)
+ goto error;
- length = header.length - sizeof(header);
- if (length > 0) {
- data = calloc(1, length);
- if (data == NULL)
- goto error;
+ rc = 0;
+ goto complete;
- FD_ZERO(&fds);
- FD_SET(client->fd, &fds);
+error:
+ rc = -1;
+
+complete:
+ if (message.data != NULL && message.size > 0)
+ free(message.data);
+
+ return rc;
+}
- rc = select(client->fd + 1, &fds, NULL, NULL, &timeout);
- if (rc <= 0 || !FD_ISSET(client->fd, &fds))
- goto error;
+/*
+ * SRS client
+ */
+
+struct srs_client *srs_client_create(void)
+{
+ struct srs_client *client;
+
+ signal(SIGPIPE, SIG_IGN);
- SRS_CLIENT_LOCK(client);
- rc = read(client->fd, data, length);
- SRS_CLIENT_UNLOCK(client);
+ client = (struct srs_client *) calloc(1, sizeof(struct srs_client));
+ client->fd = -1;
+ client->event_fd = -1;
- if (rc != length)
- goto error;
+ pthread_mutex_init(&client->mutex, NULL);
- message->data = data;
- message->length = length;
- }
+ return client;
+}
+
+int srs_client_destroy(struct srs_client *client)
+{
+ if (client == NULL)
+ return -1;
- rc = header.length;
- goto done;
+ pthread_mutex_destroy(&client->mutex);
+
+ memset(client, 0, sizeof(struct srs_client));
+ free(client);
+
+ return 0;
+}
+
+int srs_client_open(struct srs_client *client)
+{
+ int flags;
+ int fd = 0;
+ int i = 0;
+ int rc;
+
+ if (client == NULL)
+ return -1;
+
+ SRS_CLIENT_LOCK(client);
+
+ do {
+ if (fd < 0)
+ usleep(50000);
+
+#if RIL_VERSION >= 6
+ fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+#else
+ fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+#endif
+
+ flags = fcntl(fd, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(fd, F_SETFL, flags);
+
+ i++;
+ } while (fd < 0 && i < 5);
+
+ if (fd < 0)
+ goto error;
+
+ client->fd = fd;
+
+ rc = 0;
+ goto complete;
error:
rc = -1;
- if (data != NULL)
- free(data);
+complete:
+ SRS_CLIENT_UNLOCK(client);
-done:
return rc;
}
-int srs_client_send_message(struct srs_client *client, struct srs_message *message)
+int srs_client_close(struct srs_client *client)
{
- struct srs_header header;
- unsigned char *p = NULL;
- void *data = NULL;
- int length = 0;
+ if (client == NULL )
+ return -1;
+
+ SRS_CLIENT_LOCK(client);
+
+ if (client->fd >= 0) {
+ close(client->fd);
+ client->fd = -1;
+ }
+
+ SRS_CLIENT_UNLOCK(client);
+
+ return 0;
+}
+
+int srs_client_poll(struct srs_client *client)
+{
+ struct timeval timeout;
+ fd_set fds;
+ int rc;
+
+ if (client == NULL || client->fd < 0)
+ return -1;
+
+ memset(&timeout, 0, sizeof(timeout));
+ timeout.tv_usec = 50000;
+ FD_ZERO(&fds);
+ FD_SET(client->fd, &fds);
+
+ rc = select(client->fd + 1, &fds, NULL, NULL, &timeout);
+
+ return rc;
+}
+
+int srs_client_send(struct srs_client *client, unsigned short command,
+ void *data, size_t size)
+{
+ struct srs_message message;
+ struct srs_header header;
+ void *buffer = NULL;
+ size_t length;
struct timeval timeout;
fd_set fds;
+ unsigned char *p;
int rc;
- if (client == NULL || message == NULL || client->fd < 0)
- return -EINVAL;
+ if (client == NULL || client->fd < 0)
+ return -1;
+
+ SRS_CLIENT_LOCK(client);
+
+ memset(&message, 0, sizeof(message));
+ message.command = command;
+ message.data = data;
+ message.size = size;
- memset(&header, 0, sizeof(header));
- header.length = message->length + sizeof(header);
- header.group = SRS_GROUP(message->command);
- header.index = SRS_INDEX(message->command);
+ srs_header_setup(&header, &message);
length = header.length;
- data = calloc(1, length);
- if (data == NULL)
- goto error;
+ buffer = calloc(1, length);
- p = (unsigned char *) data;
- memcpy(p, &header, sizeof(header));
- p += sizeof(header);
- if (message->data != NULL && message->length > 0) {
- memcpy(p, message->data, message->length);
- p += message->length;
+ memcpy(buffer, &header, sizeof(header));
+ if (message.data != NULL && message.size > 0) {
+ p = (unsigned char *) buffer + sizeof(header);
+ memcpy(p, message.data, message.size);
}
- timeout.tv_sec = (SRS_CLIENT_TIMEOUT - SRS_CLIENT_TIMEOUT % 1000000) / 1000000;
- timeout.tv_usec = SRS_CLIENT_TIMEOUT % 1000000;
+ memset(&timeout, 0, sizeof(timeout));
+ timeout.tv_usec = 300;
FD_ZERO(&fds);
FD_SET(client->fd, &fds);
@@ -161,204 +296,224 @@ int srs_client_send_message(struct srs_client *client, struct srs_message *messa
if (rc <= 0 || !FD_ISSET(client->fd, &fds))
goto error;
- SRS_CLIENT_LOCK(client);
- rc = write(client->fd, data, length);
- SRS_CLIENT_UNLOCK(client);
-
- if (rc != length)
+ rc = write(client->fd, buffer, length);
+ if (rc < (int) length)
goto error;
- rc = length;
- goto done;
+ rc = 0;
+ goto complete;
error:
rc = -1;
-done:
- if (data != NULL)
- free(data);
+complete:
+ if (buffer != NULL)
+ free(buffer);
+
+ SRS_CLIENT_UNLOCK(client);
return rc;
}
-int srs_client_send(struct srs_client *client, unsigned short command, void *data, int length)
+int srs_client_recv(struct srs_client *client, struct srs_message *message)
{
- struct srs_message message;
+ struct srs_header *header;
+ void *buffer = NULL;
+ size_t length;
+ struct timeval timeout;
+ fd_set fds;
+ unsigned char *p;
+ int rc;
- memset(&message, 0, sizeof(message));
- message.command = command;
- message.data = data;
- message.length = length;
+ if (client == NULL || client->fd < 0 || message == NULL)
+ return -1;
- return srs_client_send_message(client, &message);
-}
+ SRS_CLIENT_LOCK(client);
-int srs_client_open(struct srs_client *client)
-{
- int fd;
+ length = SRS_BUFFER_LENGTH;
+ buffer= calloc(1, length);
- if (client == NULL)
- return -EINVAL;
-#if RIL_VERSION >= 6
- fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-#else
- fd = socket_local_client(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
-#endif
- if (fd < 0) {
- client->fd = -1;
- return -1;
- }
+ memset(&timeout, 0, sizeof(timeout));
+ timeout.tv_usec = 300;
- client->fd = fd;
- return 0;
-}
+ FD_ZERO(&fds);
+ FD_SET(client->fd, &fds);
-int srs_client_close(struct srs_client *client)
-{
- if (client == NULL || client->fd < 0)
- return -EINVAL;
+ rc = select(client->fd + 1, &fds, NULL, NULL, &timeout);
+ if (rc <= 0 || !FD_ISSET(client->fd, &fds))
+ goto error;
- close(client->fd);
- client->fd = -1;
+ rc = read(client->fd, buffer, length);
+ if (rc < (int) sizeof(struct srs_header))
+ goto error;
- return 0;
-}
+ header = (struct srs_header *) buffer;
-int srs_client_create(struct srs_client **client_p)
-{
- struct srs_client *client;
+ srs_message_setup(header, message);
- if (client_p == NULL)
- return -EINVAL;
+ length = header->length - sizeof(struct srs_header);
+ if (length > 0) {
+ message->size = length;
+ message->data = calloc(1, length);
- client = calloc(1, sizeof(struct srs_client));
- if (client == NULL) {
- *client_p = NULL;
- return -1;
+ p = (unsigned char *) buffer + sizeof(struct srs_header);
+ memcpy(message->data, p, length);
}
- client->fd = -1;
- pthread_mutex_init(&(client->mutex), NULL);
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
- *client_p = client;
+complete:
+ if (buffer != NULL)
+ free(buffer);
- return 0;
+ SRS_CLIENT_UNLOCK(client);
+
+ return rc;
}
-int srs_client_destroy(struct srs_client *client)
+int srs_client_loop(struct srs_client *client)
{
- if (client == NULL)
- return -EINVAL;
+ struct srs_message message;
+ unsigned long int event;
+ fd_set fds;
+ int fd_max;
+ int rc;
- pthread_mutex_destroy(&(client->mutex));
+ if (client == NULL || client->callback == NULL)
+ return -1;
- free(client);
+ while (1) {
+ if (client->fd < 0 || client->event_fd < 0)
+ return -1;
+
+ FD_ZERO(&fds);
+ FD_SET(client->fd, &fds);
+ FD_SET(client->event_fd, &fds);
+
+ fd_max = client->fd > client->event_fd ? client->fd : client->event_fd;
+
+ rc = select(fd_max + 1, &fds, NULL, NULL, NULL);
+ if (rc < 0)
+ return -1;
+
+ if (FD_ISSET(client->event_fd, &fds)) {
+ read(client->event_fd, &event, sizeof(event));
+ break;
+ }
+
+ if (!FD_ISSET(client->fd, &fds))
+ continue;
+
+ memset(&message, 0, sizeof(struct srs_message));
+
+ rc = srs_client_recv(client, &message);
+ if (rc < 0)
+ return -1;
+
+ client->callback(client, &message);
+
+ if (message.data != NULL && message.size > 0)
+ free(message.data);
+ }
return 0;
}
-/*
- * SRS Client thread
- */
-
void *srs_client_thread(void *data)
{
- struct srs_message message;
struct srs_client *client;
- int rc;
+ int rc = 0;
+ int i = 0;
if (data == NULL)
return NULL;
client = (struct srs_client *) data;
- if (client->thread_cb == NULL)
- goto done;
+ do {
+ if (rc < 0) {
+ rc = srs_client_close(client);
+ if (rc < 0)
+ break;
- while (client->thread_run) {
- rc = srs_client_recv_message(client, &message);
- if (rc < 0)
- goto done;
+ rc = srs_client_open(client);
+ if (rc < 0)
+ break;
+ }
- client->thread_cb(&message);
- }
+ rc = srs_client_loop(client);
-done:
- client->thread_run = 0;
+ i++;
+ } while (rc < 0 && i < 5);
- return NULL;
+ return 0;
}
-int srs_client_thread_start(struct srs_client *client,
- srs_client_thread_cb cb)
+int srs_client_loop_start(struct srs_client *client,
+ void (*callback)(struct srs_client *client, struct srs_message *message))
{
pthread_attr_t attr;
+ int event_fd = -1;
int rc;
- if (client == NULL || cb == NULL)
- return -EINVAL;
+ if (client == NULL || callback == NULL)
+ return -1;
+
+ SRS_CLIENT_LOCK(client);
+
+ event_fd = eventfd(0, EFD_NONBLOCK);
+ if (event_fd < 0)
+ goto error;
- client->thread_cb = cb;
- client->thread_run = 1;
+ client->event_fd = event_fd;
+ client->callback = callback;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- rc = pthread_create(&(client->thread), &attr, srs_client_thread, (void *) client);
+ rc = pthread_create(&client->thread, &attr, srs_client_thread, (void *) client);
if (rc != 0)
- return -1;
+ goto error;
- return 0;
-}
+ rc = 0;
+ goto complete;
-int srs_client_thread_stop(struct srs_client *client)
-{
- if (client == NULL)
- return -EINVAL;
+error:
+ if (event_fd >= 0) {
+ close(event_fd);
+ client->event_fd = -1;
+ }
- client->thread_run = 0;
+ rc = -1;
- return 0;
-}
+complete:
+ SRS_CLIENT_UNLOCK(client);
-/*
- * SRS Client inline
- */
+ return rc;
+}
-int srs_client_ping(struct srs_client *client)
+int srs_client_loop_stop(struct srs_client *client)
{
- struct srs_message message;
- struct srs_control_ping ping;
- struct srs_control_ping *ping_p;
- int rc;
+ unsigned long int event;
- if (client == NULL)
+ if (client == NULL || client->event_fd < 0)
return -1;
- memset(&message, 0, sizeof(message));
-
- ping.caffe = SRS_CONTROL_CAFFE;
- rc = srs_client_send(client, SRS_CONTROL_PING, &ping, sizeof(ping));
- if (rc < 0)
- goto error;
-
- rc = srs_client_recv_message(client, &message);
- if (rc < 0 || message.length <= 0 || message.data == NULL)
- goto error;
+ SRS_CLIENT_LOCK(client);
- ping_p = (struct srs_control_ping *) message.data;
- if (ping_p->caffe != SRS_CONTROL_CAFFE)
- goto error;
+ event = 1;
+ write(client->event_fd, &event, sizeof(event));
- rc = 0;
- goto done;
+ SRS_CLIENT_UNLOCK(client);
-error:
- rc = -1;
+ pthread_join(client->thread, NULL);
-done:
- if (message.data != NULL)
- free(message.data);
+ close(client->event_fd);
+ client->event_fd = -1;
- return rc;
+ return 0;
}