/* * This file is part of Samsung-RIL. * * Copyright (C) 2011-2013 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 * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Samsung-RIL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Samsung-RIL. If not, see . */ #include #include #include #include #include #include #include #include #include #define LOG_TAG "RIL-SRS" #include #include "samsung-ril.h" #include "util.h" int srs_client_register(struct srs_client_data *srs_client_data, int fd) { struct srs_client_info *client; struct list_head *list_end; struct list_head *list; if (srs_client_data == NULL) return -1; client = calloc(1, sizeof(struct srs_client_info)); if (client == NULL) return -1; client->fd = fd; list_end = srs_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 (srs_client_data->clients == NULL) srs_client_data->clients = list; return 0; } void srs_client_unregister(struct srs_client_data *srs_client_data, struct srs_client_info *client) { struct list_head *list; if (srs_client_data == NULL || client == NULL) return; list = srs_client_data->clients; while (list != NULL) { if (list->data == (void *) client) { memset(client, 0, sizeof(struct srs_client_info)); free(client); if (list == srs_client_data->clients) srs_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 *srs_client_data) { struct srs_client_info *client; struct list_head *list; list = srs_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 *srs_client_data, int fd) { struct srs_client_info *client; struct list_head *list; list = srs_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 *srs_client_data, fd_set *fds) { struct srs_client_info *client; struct list_head *list; int fd_max; if (srs_client_data == NULL || fds == NULL) return -1; fd_max = -1; list = srs_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 *srs_client_data, fd_set *fds) { struct srs_client_info *client; struct list_head *list; int fd; if (srs_client_data == NULL || fds == NULL) return -1; list = srs_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 *srs_client_data, struct srs_message *message) { struct srs_header header; void *data; struct timeval timeout; fd_set fds; int rc; if (srs_client_data == NULL || message == NULL) return -EINVAL; memset(&header, 0, sizeof(header)); header.group = SRS_GROUP(message->command); header.index = SRS_INDEX(message->command); header.length = message->length + sizeof(header); data = calloc(1, header.length); memcpy(data, &header, sizeof(header)); memcpy((void *) ((char *) data + sizeof(header)), message->data, message->length); memset(&timeout, 0, sizeof(timeout)); timeout.tv_usec = 300; if (srs_client_data->client_fd < 0) { rc = -1; goto complete; } FD_ZERO(&fds); FD_SET(srs_client_data->client_fd, &fds); rc = select(srs_client_data->client_fd + 1, NULL, &fds, NULL, &timeout); if (!FD_ISSET(srs_client_data->client_fd, &fds)) { LOGE("SRS write select failed on fd %d", srs_client_data->client_fd); rc = -1; goto complete; } rc = write(srs_client_data->client_fd, data, header.length); if (rc < (int) sizeof(struct srs_header)) { LOGE("SRS write failed on fd %d with %d bytes", srs_client_data->client_fd, rc); rc = -1; goto complete; } complete: free(data); return rc; } int srs_client_send(struct srs_client_data *srs_client_data, unsigned short command, void *data, int length) { struct srs_client_info *client; struct srs_message message; int rc; if (srs_client_data == NULL) return -1; memset(&message, 0, sizeof(message)); message.command = command; message.length = length; message.data = data; RIL_CLIENT_LOCK(srs_client_data->client); rc = srs_client_send_message(srs_client_data, &message); RIL_CLIENT_UNLOCK(srs_client_data->client); if (rc <= 0) { LOGD("SRS client with fd %d terminated", srs_client_data->client_fd); 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; } return rc; } int srs_send(unsigned short command, void *data, int length) { struct srs_client_data *srs_client_data; int rc; if (ril_data.srs_client == NULL || ril_data.srs_client->data == NULL) return -EINVAL; srs_client_data = (struct srs_client_data *) ril_data.srs_client->data; LOGD("SEND SRS: fd=%d command=%d length=%d", srs_client_data->client_fd, command, length); if (data != NULL && length > 0) { LOGD("==== SRS DATA DUMP ===="); hex_dump(data, length); LOGD("======================="); } return srs_client_send(srs_client_data, command, data, length); } int srs_client_recv(struct srs_client_data *srs_client_data, struct srs_message *message) { struct srs_header *header; void *data; struct timeval timeout; fd_set fds; int rc; if (srs_client_data == NULL || message == NULL) return -1; data = calloc(1, SRS_DATA_MAX_SIZE); memset(&timeout, 0, sizeof(timeout)); timeout.tv_usec = 300; if (srs_client_data->client_fd < 0) { rc = -1; goto complete; } FD_ZERO(&fds); FD_SET(srs_client_data->client_fd, &fds); rc = select(srs_client_data->client_fd + 1, &fds, NULL, NULL, &timeout); if (!FD_ISSET(srs_client_data->client_fd, &fds)) { LOGE("SRS read select failed on fd %d", srs_client_data->client_fd); rc = -1; goto complete; } rc = read(srs_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", srs_client_data->client_fd, rc); rc = -1; goto complete; } header = (struct srs_header *) data; 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); } complete: free(data); return rc; } void srs_control_ping(struct srs_message *message) { int caffe; if (message == NULL || message->data == NULL || message->length < (int) sizeof(int)) return; caffe = *((int *) message->data); if (caffe == SRS_CONTROL_CAFFE) srs_send(SRS_CONTROL_PING, &caffe, sizeof(caffe)); } static int srs_server_open(void) { int server_fd; int t; 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; } return -1; } void *srs_client_read_loop(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; int rc; if (data == NULL) pthread_exit(NULL); srs_client_data = (struct srs_client_data *) data; while (srs_client_data->running) { FD_ZERO(&fds); SRS_CLIENT_LOCK(); fd_max = srs_client_info_fill_fd_set(srs_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(srs_client_data, &fds)) >= 0) { srs_client_data->client_fd = fd; RIL_CLIENT_LOCK(srs_client_data->client); rc = srs_client_recv(srs_client_data, &message); if (rc <= 0) { LOGD("SRS client with fd %d terminated", fd); client = srs_client_info_find_fd(srs_client_data, fd); if (client != NULL) srs_client_unregister(srs_client_data, client); close(fd); RIL_CLIENT_UNLOCK(srs_client_data->client); continue; } RIL_CLIENT_UNLOCK(srs_client_data->client); LOGD("RECV SRS: fd=%d command=%d length=%d", fd, message.command, message.length); if (message.data != NULL && message.length > 0) { LOGD("==== SRS DATA DUMP ===="); hex_dump(message.data, message.length); LOGD("======================="); } srs_dispatch(&message); if (message.data != NULL && message.length > 0) free(message.data); srs_client_data->client_fd = -1; } SRS_CLIENT_UNLOCK(); } pthread_exit(NULL); return NULL; } int srs_read_loop(struct ril_client *client) { struct srs_client_data *srs_client_data; struct sockaddr_un client_addr; int client_addr_len; pthread_attr_t attr; int flags; int fd; int rc; if (client == NULL || client->data == NULL) return -EINVAL; srs_client_data = (struct srs_client_data *) client->data; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); srs_client_data->running = 1; rc = pthread_create(&srs_client_data->thread, &attr, srs_client_read_loop, (void *) srs_client_data); if (rc < 0) { LOGE("Unable to create SRS client read loop thread"); 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) { LOGE("Unable to accept new SRS client"); break; } flags = fcntl(fd, F_GETFL); flags |= O_NONBLOCK; fcntl(fd, F_SETFL, flags); LOGD("Accepted new SRS client from fd %d", fd); SRS_CLIENT_LOCK(); rc = srs_client_register(srs_client_data, fd); SRS_CLIENT_UNLOCK(); if (rc < 0) { LOGE("Unable to register SRS client"); break; } } LOGE("SRS server failure"); srs_client_data->running = 0; // Wait for the thread to finish pthread_join(srs_client_data->thread, NULL); return 0; } int srs_create(struct ril_client *client) { struct srs_client_data *srs_client_data; if (client == NULL) return -EINVAL; LOGD("Creating new SRS client"); signal(SIGPIPE, SIG_IGN); srs_client_data = (struct srs_client_data *) calloc(1, sizeof(struct srs_client_data)); srs_client_data->server_fd = srs_server_open(); if (srs_client_data->server_fd < 0) { LOGE("SRS server creation failed"); goto error; } pthread_mutex_init(&srs_client_data->mutex, NULL); srs_client_data->client = client; client->data = (void *) srs_client_data; return 0; error: free(srs_client_data); return -1; } int srs_destroy(struct ril_client *client) { struct srs_client_data *srs_client_data = NULL; struct srs_client_info *client_info; if (client == NULL || client->data == NULL) { LOGE("Client was already destroyed"); return 0; } srs_client_data = (struct srs_client_data *) client->data; pthread_mutex_destroy(&srs_client_data->mutex); while ((client_info = srs_client_info_find(srs_client_data)) != NULL) { close(client_info->fd); srs_client_unregister(srs_client_data, client_info); } if (srs_client_data->server_fd > 0) close(srs_client_data->server_fd); srs_client_data->server_fd = -1; srs_client_data->client_fd = -1; srs_client_data->clients = NULL; srs_client_data->running = 0; free(srs_client_data); client->data = NULL; return 0; } struct ril_client_funcs srs_client_funcs = { .create = srs_create, .destroy = srs_destroy, .read_loop = srs_read_loop, };