From a7ff1df1869ce543171a6ee92cbf821647b1bf7d Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 7 Aug 2014 13:12:15 +0200 Subject: Samsung-RIL rewrite: harder, better, probably not faster but definitely stronger Signed-off-by: Paul Kocialkowski --- srs.c | 1181 ++++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 881 insertions(+), 300 deletions(-) (limited to 'srs.c') diff --git a/srs.c b/srs.c index b05beb3..890a33e 100644 --- a/srs.c +++ b/srs.c @@ -1,7 +1,7 @@ /* * This file is part of Samsung-RIL. * - * Copyright (C) 2011-2013 Paul Kocialkowski + * Copyright (C) 2011-2014 Paul Kocialkowski * * 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,12 +17,15 @@ * along with Samsung-RIL. If not, see . */ +#include +#include #include #include #include #include #include #include +#include #include #include @@ -30,52 +33,213 @@ #define LOG_TAG "RIL-SRS" #include +#include -#include "samsung-ril.h" -#include "util.h" +#include +#include -int srs_client_register(struct srs_client_data *srs_client_data, int fd) +/* + * Utils + */ + +const char *srs_command_string(unsigned short command) +{ + 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; + } +} + +void srs_log_send(struct ril_client *client, struct srs_message *message) { - struct srs_client_info *client; + if (client == NULL || message == NULL) + return; + + RIL_LOGD("\n"); + RIL_LOGD("%s: Sent %s message", __func__, client->name); + RIL_LOGD("%s: Message: command=%s, size=%d", __func__, srs_command_string(message->command), message->size); + if (message->size > 0) { + RIL_LOGD("=================================== %s data ===================================", client->name); + data_dump(message->data, message->size); + RIL_LOGD("================================================================================"); + } +} + +void srs_log_recv(struct ril_client *client, struct srs_message *message) +{ + if (client == NULL || message == NULL) + return; + + RIL_LOGD("\n"); + RIL_LOGD("%s: Received %s message", __func__, client->name); + RIL_LOGD("%s: Message: command=%s, size=%d", __func__, srs_command_string(message->command), message->size); + if (message->size > 0) { + RIL_LOGD("=================================== %s data ===================================", client->name); + data_dump(message->data, message->size); + RIL_LOGD("================================================================================"); + } +} + +int srs_header_setup(struct srs_header *header, + const struct srs_message *message) +{ + if (header == NULL || message == NULL) + return -1; + + 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)); + message->command = SRS_COMMAND(header->group, header->index); + message->data = NULL; + message->size = 0; + + return 0; +} + +/* + * SRS + */ + +int srs_send(unsigned short command, const void *data, size_t size) +{ + struct ril_client *ril_client; + struct srs_data *srs_data; + struct srs_client *client; + struct srs_message message; + int rc; + + ril_client = ril_client_find_id(RIL_CLIENT_SRS); + if (ril_client == NULL || ril_client->data == NULL) + return -1; + + srs_data = (struct srs_data *) ril_client->data; + if (srs_data->event_fd < 0) + return -1; + + if (!ril_client->available) { + RIL_LOGE("%s client is not available", ril_client->name); + return -1; + } + + memset(&message, 0, sizeof(message)); + message.command = command; + message.data = (void *) data; + message.size = size; + + acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING); + + rc = srs_client_send(ril_client, &message); + if (rc < 0) { + RIL_LOGE("Sending to %s client failed", ril_client->name); + + release_wake_lock(RIL_VERSION_STRING); + + eventfd_send(srs_data->event_fd, SRS_CLIENT_IO_ERROR); + return -1; + } + + return 0; +} + +int srs_control_ping(struct srs_message *message) +{ + struct srs_control_ping_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct srs_control_ping_data)) + return -1; + + data = (struct srs_control_ping_data *) message->data; + if (data->caffe == SRS_CONTROL_CAFFE) { + rc = srs_send(SRS_CONTROL_PING, data, sizeof(struct srs_control_ping_data)); + if (rc < 0) { + RIL_LOGE("Sending SRS control ping failed"); + return 0; + } + } + + return 0; +} + +/* + * SRS client + */ + +int srs_client_register(struct ril_client *ril_client, int fd) +{ + struct srs_data *data; + struct srs_client *client; struct list_head *list_end; struct list_head *list; - if (srs_client_data == NULL) + if (ril_client == NULL || ril_client->data == NULL) return -1; - client = calloc(1, sizeof(struct srs_client_info)); - if (client == NULL) - return -1; + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); + client = calloc(1, sizeof(struct srs_client)); client->fd = fd; - list_end = srs_client_data->clients; + list_end = data->clients; while (list_end != NULL && list_end->next != NULL) list_end = list_end->next; - list = list_head_alloc((void *) client, list_end, NULL); + list = list_head_alloc(list_end, NULL, (void *) client); - if (srs_client_data->clients == NULL) - srs_client_data->clients = list; + if (data->clients == NULL) + data->clients = list; + + RIL_CLIENT_UNLOCK(ril_client); return 0; } -void srs_client_unregister(struct srs_client_data *srs_client_data, struct srs_client_info *client) +int srs_client_unregister(struct ril_client *ril_client, + struct srs_client *client) { + struct srs_data *data; struct list_head *list; - if (srs_client_data == NULL || client == NULL) - return; + if (ril_client == NULL || ril_client->data == NULL) + return -1; + + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); - list = srs_client_data->clients; + list = data->clients; while (list != NULL) { if (list->data == (void *) client) { - memset(client, 0, sizeof(struct srs_client_info)); + memset(client, 0, sizeof(struct srs_client)); free(client); - if (list == srs_client_data->clients) - srs_client_data->clients = list->next; + if (list == data->clients) + data->clients = list->next; list_head_free(list); @@ -84,497 +248,914 @@ void srs_client_unregister(struct srs_client_data *srs_client_data, struct srs_c list_continue: list = list->next; } + + RIL_CLIENT_UNLOCK(ril_client); + + return 0; } -struct srs_client_info *srs_client_info_find(struct srs_client_data *srs_client_data) +int srs_client_flush(struct ril_client *ril_client) { - struct srs_client_info *client; + struct srs_data *data; + struct srs_client *client; struct list_head *list; + struct list_head *list_next; + + if (ril_client == NULL || ril_client->data == NULL) + return -1; + + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); - list = srs_client_data->clients; + list = data->clients; while (list != NULL) { - client = (struct srs_client_info *) list->data; - if (client == NULL) + if (list->data != NULL) { + client = (struct srs_client *) list->data; + memset(client, 0, sizeof(struct srs_client)); + free(client); + } + + if (list == data->clients) + data->clients = list->next; + + list_next = list->next; + + list_head_free(list); + +list_continue: + list = list_next; + } + + RIL_CLIENT_UNLOCK(ril_client); + + return 0; +} + +struct srs_client *srs_client_find(struct ril_client *ril_client) +{ + struct srs_data *data; + struct srs_client *client; + struct list_head *list; + + if (ril_client == NULL || ril_client->data == NULL) + return NULL; + + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); + + list = data->clients; + while (list != NULL) { + if (list->data == NULL) goto list_continue; + client = (struct srs_client *) list->data; + + RIL_CLIENT_UNLOCK(ril_client); return client; list_continue: list = list->next; } + RIL_CLIENT_UNLOCK(ril_client); + return NULL; } -struct srs_client_info *srs_client_info_find_fd(struct srs_client_data *srs_client_data, int fd) +struct srs_client *srs_client_find_fd(struct ril_client *ril_client, int fd) { - struct srs_client_info *client; + struct srs_data *data; + struct srs_client *client; struct list_head *list; - list = srs_client_data->clients; + if (ril_client == NULL || ril_client->data == NULL) + return NULL; + + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); + + list = data->clients; while (list != NULL) { - client = (struct srs_client_info *) list->data; - if (client == NULL) + if (list->data == NULL) goto list_continue; - if (client->fd == fd) + client = (struct srs_client *) list->data; + + if (client->fd == fd) { + RIL_CLIENT_UNLOCK(ril_client); return client; + } list_continue: list = list->next; } + RIL_CLIENT_UNLOCK(ril_client); + return NULL; } -int srs_client_info_fill_fd_set(struct srs_client_data *srs_client_data, fd_set *fds) +struct srs_client *srs_client_find_fd_set(struct ril_client *ril_client, + fd_set *fds) { - struct srs_client_info *client; + struct srs_data *data; + struct srs_client *client; struct list_head *list; - int fd_max; - if (srs_client_data == NULL || fds == NULL) - return -1; + if (ril_client == NULL || ril_client->data == NULL || fds == NULL ) + return NULL; + + data = (struct srs_data *) ril_client->data; - fd_max = -1; - list = srs_client_data->clients; + RIL_CLIENT_LOCK(ril_client); + + list = data->clients; while (list != NULL) { - client = (struct srs_client_info *) list->data; - if (client == NULL) + if (list->data == NULL) goto list_continue; - FD_SET(client->fd, fds); - if (client->fd > fd_max) - fd_max = client->fd; + client = (struct srs_client *) list->data; + + if (FD_ISSET(client->fd, fds)) { + FD_CLR(client->fd, fds); + + RIL_CLIENT_UNLOCK(ril_client); + return client; + } list_continue: list = list->next; } - return fd_max; + RIL_CLIENT_UNLOCK(ril_client); + + return NULL; } -int srs_client_info_get_fd_set(struct srs_client_data *srs_client_data, fd_set *fds) +int srs_client_fd_set_setup(struct ril_client *ril_client, fd_set *fds) { - struct srs_client_info *client; + struct srs_data *data; + struct srs_client *client; struct list_head *list; - int fd; + int fd_max = -1; - if (srs_client_data == NULL || fds == NULL) + if (ril_client == NULL || ril_client->data == NULL || fds == NULL) return -1; - list = srs_client_data->clients; + data = (struct srs_data *) ril_client->data; + + RIL_CLIENT_LOCK(ril_client); + + FD_ZERO(fds); + + list = data->clients; while (list != NULL) { - client = (struct srs_client_info *) list->data; - if (client == NULL) + if (list->data == NULL) goto list_continue; - if (FD_ISSET(client->fd, fds)) { - FD_CLR(client->fd, fds); - return client->fd; - } + client = (struct srs_client *) list->data; + + FD_SET(client->fd, fds); + if (client->fd > fd_max) + fd_max = client->fd; list_continue: list = list->next; } - return -1; + RIL_CLIENT_UNLOCK(ril_client); + + return fd_max; } -int srs_client_send_message(struct srs_client_data *srs_client_data, struct srs_message *message) +int srs_client_send(struct ril_client *client, struct srs_message *message) { + struct srs_data *data; struct srs_header header; - void *data; - + void *buffer = NULL; + size_t length; struct timeval timeout; fd_set fds; + unsigned char *p; int rc; - if (srs_client_data == NULL || message == NULL) - return -EINVAL; + if (client == NULL || client->data == NULL || message == NULL) + return -1; - memset(&header, 0, sizeof(header)); - header.group = SRS_GROUP(message->command); - header.index = SRS_INDEX(message->command); - header.length = message->length + sizeof(header); + data = (struct srs_data *) client->data; + if (data->client_fd < 0) + return -1; - data = calloc(1, header.length); - memcpy(data, &header, sizeof(header)); - memcpy((void *) ((char *) data + sizeof(header)), message->data, message->length); + RIL_CLIENT_LOCK(client); - memset(&timeout, 0, sizeof(timeout)); - timeout.tv_usec = 300; + srs_header_setup(&header, message); + + length = header.length; + buffer = calloc(1, length); - if (srs_client_data->client_fd < 0) { - rc = -1; - goto complete; + memcpy(buffer, &header, sizeof(header)); + if (message->data != NULL && message->size > 0) { + p = (unsigned char *) buffer + sizeof(header); + memcpy(p, message->data, message->size); } - FD_ZERO(&fds); - FD_SET(srs_client_data->client_fd, &fds); + srs_log_send(client, message); - rc = select(srs_client_data->client_fd + 1, NULL, &fds, NULL, &timeout); + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 300; + + FD_ZERO(&fds); + FD_SET(data->client_fd, &fds); - if (!FD_ISSET(srs_client_data->client_fd, &fds)) { - RIL_LOGE("SRS write select failed on fd %d", srs_client_data->client_fd); - rc = -1; - goto complete; + rc = select(data->client_fd + 1, NULL, &fds, NULL, &timeout); + if (rc <= 0 || !FD_ISSET(data->client_fd, &fds)) { + RIL_LOGE("Polling %s client failed", client->name); + goto error; } - rc = write(srs_client_data->client_fd, data, header.length); - if (rc < (int) sizeof(struct srs_header)) { - RIL_LOGE("SRS write failed on fd %d with %d bytes", srs_client_data->client_fd, rc); - rc = -1; - goto complete; + rc = write(data->client_fd, buffer, length); + if (rc < (int) length) { + RIL_LOGE("Writing to %s client failed", client->name); + goto error; } + rc = 0; + goto complete; + +error: + rc = -1; + complete: - free(data); + if (buffer != NULL) + free(buffer); + + RIL_CLIENT_UNLOCK(client); return rc; } -int srs_client_send(struct srs_client_data *srs_client_data, unsigned short command, void *data, int length) +int srs_client_recv(struct ril_client *client, struct srs_message *message) { - struct srs_client_info *client; - struct srs_message message; + struct srs_data *data; + struct srs_header *header; + void *buffer = NULL; + size_t length; + struct timeval timeout; + fd_set fds; + unsigned char *p; int rc; - if (srs_client_data == NULL) + if (client == NULL || client->data == NULL || message == NULL) return -1; - memset(&message, 0, sizeof(message)); - message.command = command; - message.length = length; - message.data = data; + data = (struct srs_data *) client->data; + if (data->client_fd < 0) + return -1; + + RIL_CLIENT_LOCK(client); + + length = SRS_BUFFER_LENGTH; + buffer= calloc(1, length); + + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 300; + + FD_ZERO(&fds); + FD_SET(data->client_fd, &fds); + + rc = select(data->client_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0 || !FD_ISSET(data->client_fd, &fds)) { + RIL_LOGE("Polling %s client failed", client->name); + goto error; + } + + rc = read(data->client_fd, buffer, length); + if (rc < (int) sizeof(struct srs_header)) { + RIL_LOGE("Reading from %s client failed", client->name); + goto error; + } + + header = (struct srs_header *) buffer; - RIL_CLIENT_LOCK(srs_client_data->client); - rc = srs_client_send_message(srs_client_data, &message); - RIL_CLIENT_UNLOCK(srs_client_data->client); + srs_message_setup(header, message); - if (rc <= 0) { - RIL_LOGD("SRS client with fd %d terminated", srs_client_data->client_fd); + length = header->length - sizeof(struct srs_header); + if (length > 0) { + message->size = length; + message->data = calloc(1, length); - client = srs_client_info_find_fd(srs_client_data, srs_client_data->client_fd); - if (client != NULL) - srs_client_unregister(srs_client_data, client); - close(srs_client_data->client_fd); - srs_client_data->client_fd = -1; + p = (unsigned char *) buffer + sizeof(struct srs_header); + memcpy(message->data, p, length); } + srs_log_recv(client, message); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + RIL_CLIENT_UNLOCK(client); + return rc; } -int srs_send(unsigned short command, void *data, int length) +/* + * SRS server + */ + +int srs_server_open(struct ril_client *client) { - struct srs_client_data *srs_client_data; + struct srs_data *data; + int server_fd; + int flags; int rc; - if (ril_data.srs_client == NULL || ril_data.srs_client->data == NULL) - return -EINVAL; + if (client == NULL || client->data == NULL) + return -1; + + data = (struct srs_data *) client->data; + if (data->server_event_fd < 0) + return -1; - srs_client_data = (struct srs_client_data *) ril_data.srs_client->data; + RIL_CLIENT_LOCK(client); - RIL_LOGD("SEND SRS: fd=%d command=%d length=%d", srs_client_data->client_fd, command, length); - if (data != NULL && length > 0) { - RIL_LOGD("==== SRS DATA DUMP ===="); - hex_dump(data, length); - RIL_LOGD("======================="); + unlink(SRS_SOCKET_NAME); + +#if RIL_VERSION >= 6 + server_fd = socket_local_server(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); +#else + server_fd = socket_local_server(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); +#endif + if (server_fd < 0) { + RIL_LOGE("Opening %s server failed", client->name); + goto error; } - return srs_client_send(srs_client_data, command, data, length); + flags = fcntl(server_fd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(server_fd, F_SETFL, flags); + + data->server_fd = server_fd; + + eventfd_flush(data->server_event_fd); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); + + return rc; } -int srs_client_recv(struct srs_client_data *srs_client_data, struct srs_message *message) +int srs_server_close(struct ril_client *ril_client) { - struct srs_header *header; - void *data; - - struct timeval timeout; - fd_set fds; + struct srs_data *data; + struct srs_client *client; + eventfd_t event; int rc; - if (srs_client_data == NULL || message == NULL) + if (ril_client == NULL || ril_client->data == NULL) return -1; - data = calloc(1, SRS_DATA_MAX_SIZE); + data = (struct srs_data *) ril_client->data; + if (data->server_event_fd < 0) + return -1; - memset(&timeout, 0, sizeof(timeout)); - timeout.tv_usec = 300; + do { + client = srs_client_find(ril_client); + if (client == NULL) + break; - if (srs_client_data->client_fd < 0) { - rc = -1; - goto complete; - } + if (client->fd >= 0) + close(client->fd); - FD_ZERO(&fds); - FD_SET(srs_client_data->client_fd, &fds); + rc = srs_client_unregister(ril_client, client); + if (rc < 0) { + RIL_LOGE("Unregistering %s client failed", ril_client->name); + return -1; + } + } while (client != NULL); - rc = select(srs_client_data->client_fd + 1, &fds, NULL, NULL, &timeout); + RIL_CLIENT_LOCK(ril_client); - if (!FD_ISSET(srs_client_data->client_fd, &fds)) { - RIL_LOGE("SRS read select failed on fd %d", srs_client_data->client_fd); - rc = -1; - goto complete; + rc = eventfd_send(data->server_event_fd, SRS_SERVER_CLOSE); + if (rc < 0) { + RIL_LOGE("Sending %s server close event failed", ril_client->name); + goto error; } - rc = read(srs_client_data->client_fd, data, SRS_DATA_MAX_SIZE); - if (rc < (int) sizeof(struct srs_header)) { - RIL_LOGE("SRS read failed on fd %d with %d bytes", srs_client_data->client_fd, rc); - rc = -1; - goto complete; + if (data->server_fd >= 0) { + close(data->server_fd); + data->server_fd = -1; } - header = (struct srs_header *) data; + rc = 0; + goto complete; - memset(message, 0, sizeof(struct srs_message)); - message->command = SRS_COMMAND(header); - message->length = header->length - sizeof(struct srs_header); - message->data = NULL; - - if (message->length > 0) { - message->data = calloc(1, message->length); - memcpy(message->data, (void *) ((char *) data + sizeof(struct srs_header)), message->length); - } +error: + rc = -1; complete: - free(data); + RIL_CLIENT_UNLOCK(ril_client); return rc; } -void srs_control_ping(struct srs_message *message) +int srs_server_loop(struct ril_client *client) { - int caffe; + struct srs_data *data; + struct sockaddr_un client_addr; + socklen_t client_addr_len; + eventfd_t event; + int client_fd; + fd_set fds; + int fd_max; + int flags; + int rc; - if (message == NULL || message->data == NULL || message->length < (int) sizeof(int)) - return; + if (client == NULL || client->data == NULL) + return -1; - caffe = *((int *) message->data); + data = (struct srs_data *) client->data; + if (data->server_fd < 0 || data->server_event_fd < 0 || data->event_fd < 0) + return -1; - if (caffe == SRS_CONTROL_CAFFE) - srs_send(SRS_CONTROL_PING, &caffe, sizeof(caffe)); -} + while (1) { + if (!client->available) { + RIL_LOGE("%s client is not available", client->name); + return -1; + } -static int srs_server_open(void) -{ - int server_fd; - int t; + FD_ZERO(&fds); + FD_SET(data->server_fd, &fds); + FD_SET(data->server_event_fd, &fds); - 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); -#else - server_fd = socket_local_server(SRS_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); -#endif - if (server_fd >= 0) - return server_fd; + fd_max = data->server_fd > data->server_event_fd ? data->server_fd : data->server_event_fd; + + rc = select(fd_max + 1, &fds, NULL, NULL, NULL); + if (rc < 0) { + RIL_LOGE("Polling %s server failed", client->name); + return -1; + } + + if (FD_ISSET(data->server_event_fd, &fds)) { + rc = eventfd_recv(data->server_event_fd, &event); + if (rc < 0) + return -1; + + switch (event) { + case SRS_SERVER_CLOSE: + return 0; + } + } + + if (!FD_ISSET(data->server_fd, &fds)) + continue; + + client_fd = accept(data->server_fd, (struct sockaddr *) &client_addr, &client_addr_len); + if (client_fd < 0) { + RIL_LOGE("Accepting new %s client failed", client->name); + return -1; + } + + flags = fcntl(client_fd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(client_fd, F_SETFL, flags); + + rc = srs_client_register(client, client_fd); + if (rc < 0) { + RIL_LOGE("Registering new %s client failed", client->name); + return -1; + } + + RIL_LOGD("Registered new %s client", client->name); + + rc = eventfd_send(data->event_fd, SRS_CLIENT_CHANGE); + if (rc < 0) { + RIL_LOGE("Sending %s change event failed", client->name); + return -1; + } } - return -1; + return 0; } -void *srs_client_read_loop(void *data) +void *srs_server_thread(void *data) { - struct srs_client_info *client; - struct srs_client_data *srs_client_data; - struct srs_message message; - struct timeval timeout; - fd_set fds; - int fd_max; - int fd; + struct ril_client *client; + int failures = 0; int rc; if (data == NULL) - pthread_exit(NULL); + return NULL; - srs_client_data = (struct srs_client_data *) data; + client = (struct ril_client *) data; - while (srs_client_data->running) { - FD_ZERO(&fds); + do { + if (failures) { + rc = srs_server_close(client); + if (rc < 0) + goto failure; - SRS_CLIENT_LOCK(); - fd_max = srs_client_info_fill_fd_set(srs_client_data, &fds); - SRS_CLIENT_UNLOCK(); + rc = srs_server_open(client); + if (rc < 0) + goto failure; + } - if (fd_max < 0) { - usleep(3000); - continue; + rc = srs_server_loop(client); + if (rc < 0) { + RIL_LOGE("%s server loop failed", client->name); + goto failure; + } else { + RIL_LOGE("%s server loop terminated", client->name); + break; } - timeout.tv_sec = 0; - timeout.tv_usec = 3000; +failure: + failures++; + } while (failures < RIL_CLIENT_RETRY_COUNT); - select(fd_max + 1, &fds, NULL, NULL, &timeout); + srs_server_close(client); - SRS_CLIENT_LOCK(); - while ((fd = srs_client_info_get_fd_set(srs_client_data, &fds)) >= 0) { - srs_client_data->client_fd = fd; + RIL_LOGD("Stopped %s server loop", client->name); - RIL_CLIENT_LOCK(srs_client_data->client); - rc = srs_client_recv(srs_client_data, &message); - if (rc <= 0) { - RIL_LOGD("SRS client with fd %d terminated", fd); + return NULL; +} - client = srs_client_info_find_fd(srs_client_data, fd); - if (client != NULL) - srs_client_unregister(srs_client_data, client); - close(fd); +/* + * SRS client + */ - RIL_CLIENT_UNLOCK(srs_client_data->client); - continue; - } - RIL_CLIENT_UNLOCK(srs_client_data->client); +int srs_create(struct ril_client *client) +{ + struct srs_data *data; + int server_event_fd = -1; + int event_fd = -1; + int rc; - RIL_LOGD("RECV SRS: fd=%d command=%d length=%d", fd, message.command, message.length); - if (message.data != NULL && message.length > 0) { - RIL_LOGD("==== SRS DATA DUMP ===="); - hex_dump(message.data, message.length); - RIL_LOGD("======================="); - } + if (client == NULL) + return -1; - srs_dispatch(&message); + signal(SIGPIPE, SIG_IGN); - if (message.data != NULL && message.length > 0) - free(message.data); + RIL_CLIENT_LOCK(client); - srs_client_data->client_fd = -1; - } - SRS_CLIENT_UNLOCK(); + client->available = 0; + + data = (struct srs_data *) calloc(1, sizeof(struct srs_data)); + data->server_fd = -1; + data->client_fd = -1; + + server_event_fd = eventfd(0, EFD_NONBLOCK); + if (server_event_fd < 0) { + RIL_LOGE("Creating %s server event failed", client->name); + goto error; } - pthread_exit(NULL); - return NULL; + event_fd = eventfd(0, EFD_NONBLOCK); + if (event_fd < 0) { + RIL_LOGE("Creating %s event failed", client->name); + goto error; + } + + data->server_event_fd = server_event_fd; + data->event_fd = event_fd; + + client->data = data; + + rc = 0; + goto complete; + +error: + if (server_event_fd >= 0) + close(server_event_fd); + + if (event_fd >= 0) + close(event_fd); + + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); + + return rc; } -int srs_read_loop(struct ril_client *client) +int srs_destroy(struct ril_client *client) { - struct srs_client_data *srs_client_data; + struct srs_data *data; - struct sockaddr_un client_addr; - int client_addr_len; + if (client == NULL || client->data == NULL) + return -1; + + data = (struct srs_data *) client->data; + + if (client->available) + srs_close(client); + + RIL_CLIENT_LOCK(client); + + client->available = 0; + + if (data->server_event_fd >= 0) + close(data->server_event_fd); + + if (data->event_fd >= 0) + close(data->event_fd); + + memset(data, 0, sizeof(struct srs_data)); + free(data); + + client->data = NULL; + + RIL_CLIENT_UNLOCK(client); + + return 0; +} + +int srs_open(struct ril_client *client) +{ + struct srs_data *data; pthread_attr_t attr; - int flags; - int fd; int rc; if (client == NULL || client->data == NULL) - return -EINVAL; + return -1; - srs_client_data = (struct srs_client_data *) client->data; + data = (struct srs_data *) client->data; + if (data->event_fd < 0) + return -1; + + rc = srs_server_open(client); + if (rc < 0) { + RIL_LOGE("Opening %s server failed", client->name); + return -1; + } + + RIL_CLIENT_LOCK(client); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - srs_client_data->running = 1; + rc = pthread_create(&data->server_thread, &attr, srs_server_thread, (void *) client); + if (rc != 0) { + RIL_LOGE("Starting %s server loop failed", client->name); + goto error; + } - rc = pthread_create(&srs_client_data->thread, &attr, srs_client_read_loop, (void *) srs_client_data); - if (rc < 0) { - RIL_LOGE("Unable to create SRS client read loop thread"); + RIL_LOGD("Started %s server loop", client->name); + + eventfd_flush(data->event_fd); + + client->available = 1; + + rc = 0; + goto complete; + +error: + srs_server_close(client); + + rc = -1; + +complete: + RIL_CLIENT_UNLOCK(client); + + return rc; +} + +int srs_close(struct ril_client *ril_client) +{ + struct srs_data *data; + struct srs_client *client; + eventfd_t event; + int rc; + + if (ril_client == NULL || ril_client->data == NULL) return -1; - } - while (srs_client_data->server_fd >= 0) { - fd = accept(srs_client_data->server_fd, (struct sockaddr *) &client_addr, - &client_addr_len); - if (fd < 0) { - RIL_LOGE("Unable to accept new SRS client"); - break; - } + data = (struct srs_data *) ril_client->data; + if (data->event_fd < 0) + return -1; - flags = fcntl(fd, F_GETFL); - flags |= O_NONBLOCK; - fcntl(fd, F_SETFL, flags); + RIL_CLIENT_LOCK(ril_client); - RIL_LOGD("Accepted new SRS client from fd %d", fd); + rc = eventfd_send(data->event_fd, SRS_CLIENT_CLOSE); + if (rc < 0) { + RIL_LOGE("Sending %s close event failed", ril_client->name); + RIL_CLIENT_UNLOCK(ril_client); - SRS_CLIENT_LOCK(); - rc = srs_client_register(srs_client_data, fd); - SRS_CLIENT_UNLOCK(); - if (rc < 0) { - RIL_LOGE("Unable to register SRS client"); - break; - } + return -1; } - RIL_LOGE("SRS server failure"); + data->client_fd = -1; + + RIL_CLIENT_UNLOCK(ril_client); + + rc = srs_server_close(ril_client); + if (rc < 0) { + RIL_LOGE("Closing %s server failed", ril_client->name); + return -1; + } - srs_client_data->running = 0; + rc = srs_client_flush(ril_client); + if (rc < 0) { + RIL_LOGE("Flushing %s client failed", ril_client->name); + return -1; + } - // Wait for the thread to finish - pthread_join(srs_client_data->thread, NULL); + pthread_join(data->server_thread, NULL); return 0; } -int srs_create(struct ril_client *client) +int srs_dispatch(struct ril_client *client, struct srs_message *message) { - struct srs_client_data *srs_client_data; + unsigned int i; + int rc; - if (client == NULL) - return -EINVAL; + if (client == NULL || message == NULL || ril_data == NULL) + return -1; - RIL_LOGD("Creating new SRS client"); + RIL_LOCK(); - signal(SIGPIPE, SIG_IGN); + for (i = 0; i < srs_dispatch_handlers_count; i++) { + if (srs_dispatch_handlers[i].handler == NULL) + continue; - srs_client_data = (struct srs_client_data *) calloc(1, sizeof(struct srs_client_data)); + if (srs_dispatch_handlers[i].command == message->command) { + rc = srs_dispatch_handlers[i].handler(message); + if (rc < 0) { + RIL_LOGE("Handling %s message failed", client->name); + goto error; + } - srs_client_data->server_fd = srs_server_open(); - if (srs_client_data->server_fd < 0) { - RIL_LOGE("SRS server creation failed"); - goto error; + rc = 0; + goto complete; + } } - pthread_mutex_init(&srs_client_data->mutex, NULL); - - srs_client_data->client = client; - client->data = (void *) srs_client_data; + RIL_LOGD("Unhandled %s message: %s", client->name, srs_command_string(message->command)); - return 0; + rc = 0; + goto complete; error: - free(srs_client_data); + rc = -1; - return -1; +complete: + RIL_UNLOCK(); + + return rc; } -int srs_destroy(struct ril_client *client) +int srs_loop(struct ril_client *ril_client) { - struct srs_client_data *srs_client_data = NULL; - struct srs_client_info *client_info; + struct srs_data *data; + struct srs_client *client; + struct srs_message message; + eventfd_t event; + fd_set fds; + int fd_max; + int rc; - if (client == NULL || client->data == NULL) { - RIL_LOGE("Client was already destroyed"); - return 0; - } + if (ril_client == NULL || ril_client->data == NULL) + return -1; + + data = (struct srs_data *) ril_client->data; + if (data->event_fd < 0) + return -1; - srs_client_data = (struct srs_client_data *) client->data; + while (1) { + if (!ril_client->available) { + RIL_LOGE("%s client is not available", ril_client->name); + return -1; + } - pthread_mutex_destroy(&srs_client_data->mutex); + fd_max = srs_client_fd_set_setup(ril_client, &fds); - while ((client_info = srs_client_info_find(srs_client_data)) != NULL) { - close(client_info->fd); - srs_client_unregister(srs_client_data, client_info); - } + FD_SET(data->event_fd, &fds); - if (srs_client_data->server_fd > 0) - close(srs_client_data->server_fd); + fd_max = fd_max > data->event_fd ? fd_max : data->event_fd; - srs_client_data->server_fd = -1; - srs_client_data->client_fd = -1; - srs_client_data->clients = NULL; - srs_client_data->running = 0; + rc = select(fd_max + 1, &fds, NULL, NULL, NULL); + if (rc < 0) { + RIL_LOGE("Polling %s client failed", ril_client->name); + return -1; + } - free(srs_client_data); - client->data = NULL; + if (FD_ISSET(data->event_fd, &fds)) { + rc = eventfd_read(data->event_fd, &event); + if (rc < 0) + return -1; + + switch (event) { + case SRS_CLIENT_CLOSE: + return 0; + case SRS_CLIENT_CHANGE: + break; + case SRS_CLIENT_IO_ERROR: + if (client->fd >= 0) + close(client->fd); + + data->client_fd = -1; + + srs_client_unregister(ril_client, client); + break; + } + } + + do { + client = srs_client_find_fd_set(ril_client, &fds); + if (client == NULL) + break; + + data->client_fd = client->fd; + + memset(&message, 0, sizeof(message)); + + RIL_LOCK(); + acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING); + + rc = srs_client_recv(ril_client, &message); + if (rc < 0) { + RIL_LOGE("Receiving from %s client failed", ril_client->name); + + release_wake_lock(RIL_VERSION_STRING); + RIL_UNLOCK(); + + if (client->fd >= 0) + close(client->fd); + + data->client_fd = -1; + + srs_client_unregister(ril_client, client); + continue; + } + + RIL_UNLOCK(); + + rc = srs_dispatch(ril_client, &message); + if (rc < 0) { + RIL_LOGE("Dispatching %s message failed", ril_client->name); + + if (message.data != NULL && message.size > 0) + free(message.data); + + if (client->fd >= 0) + close(client->fd); + + data->client_fd = -1; + + srs_client_unregister(ril_client, client); + continue; + } + + if (message.data != NULL && message.size > 0) + free(message.data); + + data->client_fd = -1; + } while (client != NULL); + } return 0; } -struct ril_client_funcs srs_client_funcs = { +/* + * RIL client + */ + +struct ril_client_handlers srs_handlers = { .create = srs_create, .destroy = srs_destroy, - .read_loop = srs_read_loop, + .open = srs_open, + .close = srs_close, + .loop = srs_loop, +}; + + +struct ril_client_callbacks srs_callbacks = { + .request_register = NULL, + .request_unregister = NULL, + .flush = NULL, +}; + +struct ril_client srs_client = { + .id = RIL_CLIENT_SRS, + .name = "SRS", + .critical = 0, + .handlers = &srs_handlers, + .callbacks = &srs_callbacks, }; -- cgit v1.1