diff options
Diffstat (limited to 'srs-client')
-rw-r--r-- | srs-client/include/srs-client.h | 47 | ||||
-rw-r--r-- | srs-client/srs-client.c | 551 |
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; } |