From c78d57e495bde614dfd455ab93572e6d03500f53 Mon Sep 17 00:00:00 2001 From: Jinhyung Choi Date: Tue, 1 Jul 2014 10:52:19 +0900 Subject: [PATCH] guest server: changed as sdb notification server Current guest server supports 3 operations. 1. enabling sdb shell from emulator 2. registering sdb server w/ address, port, and serial 3. sending notification to registered sdb server suspend/resume message Because guest server's functionalities are changed, its name is also changed to "SDB Notification Server" It moved into sdb_noti_server.c and sdb_noti_server.h It does not require to create a new thread and blocking socket. Now, it is using g_io_add_watch to receive and handle messages from others. Change-Id: I034122842e6cc59e753b859eb057b012f43213aa Signed-off-by: Jinhyung Choi --- tizen/src/Makefile.objs | 4 +- tizen/src/ecs/ecs.c | 1 - tizen/src/emulator.c | 4 +- tizen/src/emulator_legacy.c | 1 - tizen/src/guest_server.c | 660 ------------------ tizen/src/hw/maru_pm.c | 2 +- tizen/src/sdb_noti_server.c | 430 ++++++++++++ .../src/{guest_server.h => sdb_noti_server.h} | 23 +- 8 files changed, 445 insertions(+), 680 deletions(-) delete mode 100644 tizen/src/guest_server.c create mode 100644 tizen/src/sdb_noti_server.c rename tizen/src/{guest_server.h => sdb_noti_server.h} (68%) diff --git a/tizen/src/Makefile.objs b/tizen/src/Makefile.objs index d502f85ad1..2a6d433b42 100644 --- a/tizen/src/Makefile.objs +++ b/tizen/src/Makefile.objs @@ -23,8 +23,8 @@ obj-y += tethering/ # maru skin obj-y += skin/ -# guest server -obj-y += guest_server.o +# sdb noti server +obj-y += sdb_noti_server.o # debug channel obj-y += debug_ch.o diff --git a/tizen/src/ecs/ecs.c b/tizen/src/ecs/ecs.c index ee7c3baa84..c9af67688e 100644 --- a/tizen/src/ecs/ecs.c +++ b/tizen/src/ecs/ecs.c @@ -48,7 +48,6 @@ #include "emulator.h" #include "util/sdb.h" #include "ecs.h" -#include "guest_server.h" #include "emul_state.h" #include "genmsg/ecs.pb-c.h" diff --git a/tizen/src/emulator.c b/tizen/src/emulator.c index 8538bcd9f3..7bc6d19c40 100644 --- a/tizen/src/emulator.c +++ b/tizen/src/emulator.c @@ -37,7 +37,7 @@ #include "build_info.h" #include "emulator.h" #include "emul_state.h" -#include "guest_server.h" +#include "sdb_noti_server.h" #include "emulator_options.h" #include "util/check_gl.h" #include "maru_err_table.h" @@ -253,7 +253,7 @@ static void prepare_basic_features(gchar * const kernel_cmdline) qemu_add_opts(&qemu_ecs_opts); start_ecs(); - start_guest_server(get_device_serial_number() + SDB_UDP_SENSOR_INDEX); + start_sdb_noti_server(get_device_serial_number() + SDB_UDP_SENSOR_INDEX); sdb_setup(); diff --git a/tizen/src/emulator_legacy.c b/tizen/src/emulator_legacy.c index 096114c76e..721c8c8ad4 100644 --- a/tizen/src/emulator_legacy.c +++ b/tizen/src/emulator_legacy.c @@ -39,7 +39,6 @@ #include "emulator.h" #include "emul_state.h" #include "guest_debug.h" -#include "guest_server.h" #include "hw/maru_virtio_touchscreen.h" #include "util/check_gl.h" #include "maru_err_table.h" diff --git a/tizen/src/guest_server.c b/tizen/src/guest_server.c deleted file mode 100644 index 51365f38f1..0000000000 --- a/tizen/src/guest_server.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * - * - * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: - * JiHye Kim - * GiWoong Kim - * YeongKyoon Lee - * HyunJun Son - * - * This program 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 2 - * of the License, or (at your option) any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributors: - * - S-Core Co., Ltd - * - */ - - -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#include -#else -#include -#endif - -#include "qemu/sockets.h" -#include "emulator.h" -#include "guest_server.h" -#include "skin/maruskin_server.h" -#include "debug_ch.h" -#include "util/sdb.h" -#include "maru_common.h" -#include "hw/maru_virtio_hwkey.h" -#include "hw/maru_pm.h" -#include "ecs/ecs.h" - -MULTI_DEBUG_CHANNEL(qemu, guest_server); - -#define RECV_BUF_SIZE 32 - -static int svr_port = 0; -static int server_sock = 0; - -/* - * SDB server data - */ -typedef struct GS_Client { - int port; - struct sockaddr_in addr; - char serial[RECV_BUF_SIZE]; - - QTAILQ_ENTRY(GS_Client) next; -} GS_Client; - -static QTAILQ_HEAD(GS_ClientHead, GS_Client) -clients = QTAILQ_HEAD_INITIALIZER(clients); - -static QemuThread guest_thread_id; -static QemuMutex mutex_clients; -static int running = 0; - -static void remove_sdb_client(GS_Client* client) -{ - if (client == NULL) { - return; - } - - qemu_mutex_lock(&mutex_clients); - - QTAILQ_REMOVE(&clients, client, next); - - qemu_mutex_unlock(&mutex_clients); - - g_free(client); -} - -static void send_to_sdb_client(GS_Client* client, int state) -{ - struct sockaddr_in sock_addr; - int s, slen = sizeof(sock_addr); - int serial_len = 0; - char buf [32]; - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){ - INFO("socket creation error! %d\n", errno); - return; - } - - memset(&sock_addr, 0, sizeof(sock_addr)); - - sock_addr.sin_family = AF_INET; - sock_addr.sin_port = htons(client->port); - sock_addr.sin_addr = (client->addr).sin_addr; - - if (connect(s, (struct sockaddr*)&sock_addr, slen) == -1) { - INFO("connect error! remove this client.\n"); - remove_sdb_client(client); - close(s); - return; - } - - memset(buf, 0, sizeof(buf)); - - serial_len = strlen(client->serial); - - // send message "[4 digit message length]host:sync:emulator-26101:[0|1]" - sprintf(buf, "%04xhost:sync:%s:%01d", (serial_len + 12), client->serial, state); - - INFO("send %s to client %s\n", buf, inet_ntoa(client->addr.sin_addr)); - - if (send(s, buf, sizeof(buf), 0) == -1) - { - INFO("send error! remove this client.\n"); - remove_sdb_client(client); - } - - close(s); -} - -void notify_all_sdb_clients(int state) -{ - qemu_mutex_lock(&mutex_clients); - GS_Client *client, *next; - - QTAILQ_FOREACH_SAFE(client, &clients, next, next) - { - send_to_sdb_client(client, state); - } - qemu_mutex_unlock(&mutex_clients); - -} - -static void add_sdb_client(struct sockaddr_in* addr, int port, const char* serial) -{ - GS_Client *cli = NULL; - GS_Client *client = NULL, *next; - - if (addr == NULL) { - INFO("GS_Client client's address is EMPTY.\n"); - return; - } else if (serial == NULL || strlen(serial) <= 0) { - INFO("GS_Client client's serial is EMPTY.\n"); - return; - } else if (strlen(serial) > RECV_BUF_SIZE) { - INFO("GS_Client client's serial is too long. %s\n", serial); - return; - } - - qemu_mutex_lock(&mutex_clients); - QTAILQ_FOREACH_SAFE(cli, &clients, next, next) - { - if (!strcmp(serial, cli->serial) && !strcmp(inet_ntoa(addr->sin_addr), inet_ntoa((cli->addr).sin_addr))) { - INFO("Client cannot be duplicated.\n"); - qemu_mutex_unlock(&mutex_clients); - return; - } - } - qemu_mutex_unlock(&mutex_clients); - - client = g_malloc0(sizeof(GS_Client)); - if (NULL == client) { - INFO("GS_Client allocation failed.\n"); - return; - } - - memcpy(&client->addr, addr, sizeof(struct sockaddr_in)); - client->port = port; - strcpy(client->serial, serial); - - qemu_mutex_lock(&mutex_clients); - - QTAILQ_INSERT_TAIL(&clients, client, next); - - qemu_mutex_unlock(&mutex_clients); - - INFO("Added new sdb client. ip: %s, port: %d, serial: %s\n", inet_ntoa((client->addr).sin_addr), client->port, client->serial); - - send_to_sdb_client(client, runstate_check(RUN_STATE_SUSPENDED)); -} - -static int parse_val(char* buff, unsigned char data, char* parsbuf) -{ - int count = 0; - - while (1) { - if (count > 12) { - return -1; - } - - if (buff[count] == data) { - count++; - strncpy(parsbuf, buff, count); - return count; - } - - count++; - } - - return 0; -} -#if 0 -/* - * In case that SDK does not refer to sdk.info to get tizen-sdk-data path. - * When SDK is not installed by the latest SDK installer, - * SDK installed path is fixed and there is no sdk.info file. - */ -static gchar *get_old_tizen_sdk_data_path(void) -{ - gchar *tizen_sdk_data_path = NULL; - - INFO("try to search tizen-sdk-data path in another way.\n"); - -#ifndef CONFIG_WIN32 - gchar tizen_sdk_data[] = "/tizen-sdk-data"; - gint tizen_sdk_data_len = 0; - gchar *home_dir; - - home_dir = (gchar *)g_getenv("HOME"); - if (!home_dir) { - home_dir = (gchar *)g_get_home_dir(); - } - - tizen_sdk_data_len = strlen(home_dir) + sizeof(tizen_sdk_data) + 1; - tizen_sdk_data_path = g_malloc(tizen_sdk_data_len); - if (!tizen_sdk_data_path) { - INFO("failed to allocate memory.\n"); - return NULL; - } - g_strlcpy(tizen_sdk_data_path, home_dir, tizen_sdk_data_len); - g_strlcat(tizen_sdk_data_path, tizen_sdk_data, tizen_sdk_data_len); - -#else - gchar tizen_sdk_data[] = "\\tizen-sdk-data\\"; - gint tizen_sdk_data_len = 0; - HKEY hKey; - char strLocalAppDataPath[1024] = { 0 }; - DWORD dwBufLen = 1024; - - RegOpenKeyEx(HKEY_CURRENT_USER, - "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", - 0, KEY_QUERY_VALUE, &hKey); - - RegQueryValueEx(hKey, "Local AppData", NULL, - NULL, (LPBYTE)strLocalAppDataPath, &dwBufLen); - RegCloseKey(hKey); - - tizen_sdk_data_len = strlen(strLocalAppDataPath) + sizeof(tizen_sdk_data) + 1; - tizen_sdk_data_path = g_malloc(tizen_sdk_data_len); - if (!tizen_sdk_data_path) { - INFO("failed to allocate memory.\n"); - return NULL; - } - - g_strlcpy(tizen_sdk_data_path, strLocalAppDataPath, tizen_sdk_data_len); - g_strlcat(tizen_sdk_data_path, tizen_sdk_data, tizen_sdk_data_len); -#endif - - INFO("tizen-sdk-data path: %s\n", tizen_sdk_data_path); - return tizen_sdk_data_path; -} - - - -/* - * get tizen-sdk-data path from sdk.info. - */ -gchar *get_tizen_sdk_data_path(void) -{ - gchar *emul_bin_path = NULL; - gchar *sdk_info_file_path = NULL; - gchar *tizen_sdk_data_path = NULL; -#ifndef CONFIG_WIN32 - const char *sdk_info = "../../../sdk.info"; -#else - const char *sdk_info = "..\\..\\..\\sdk.info"; -#endif - const char sdk_data_var[] = "TIZEN_SDK_DATA_PATH"; - - FILE *sdk_info_fp = NULL; - int sdk_info_path_len = 0; - - TRACE("%s\n", __func__); - - emul_bin_path = get_bin_path(); - if (!emul_bin_path) { - INFO("failed to get emulator path.\n"); - return NULL; - } - - sdk_info_path_len = strlen(emul_bin_path) + strlen(sdk_info) + 1; - sdk_info_file_path = g_malloc(sdk_info_path_len); - if (!sdk_info_file_path) { - INFO("failed to allocate sdk-data buffer.\n"); - return NULL; - } - - g_snprintf(sdk_info_file_path, sdk_info_path_len, "%s%s", - emul_bin_path, sdk_info); - INFO("sdk.info path: %s\n", sdk_info_file_path); - - sdk_info_fp = fopen(sdk_info_file_path, "r"); - g_free(sdk_info_file_path); - - if (sdk_info_fp) { - INFO("Succeeded to open [sdk.info].\n"); - - char tmp[256] = { '\0', }; - char *tmpline = NULL; - while (fgets(tmp, sizeof(tmp), sdk_info_fp) != NULL) { - if ((tmpline = g_strstr_len(tmp, sizeof(tmp), sdk_data_var))) { - tmpline += strlen(sdk_data_var) + 1; // 1 for '=' - break; - } - } - - if (tmpline) { - if (tmpline[strlen(tmpline) - 1] == '\n') { - tmpline[strlen(tmpline) - 1] = '\0'; - } - if (tmpline[strlen(tmpline) - 1] == '\r') { - tmpline[strlen(tmpline) - 1] = '\0'; - } - - tizen_sdk_data_path = g_malloc(strlen(tmpline) + 1); - g_strlcpy(tizen_sdk_data_path, tmpline, strlen(tmpline) + 1); - - INFO("tizen-sdk-data path: %s\n", tizen_sdk_data_path); - - fclose(sdk_info_fp); - return tizen_sdk_data_path; - } - - fclose(sdk_info_fp); - } - - // legacy mode - INFO("Failed to open [sdk.info].\n"); - - return get_old_tizen_sdk_data_path(); -} - -static char* get_emulator_sdcard_path(void) -{ - gchar *emulator_sdcard_path = NULL; - gchar *tizen_sdk_data = NULL; -#ifndef CONFIG_WIN32 - char emulator_sdcard[] = "/emulator/sdcard/"; -#else - char emulator_sdcard[] = "\\emulator\\sdcard\\"; -#endif - - TRACE("emulator_sdcard: %s, %d\n", emulator_sdcard, sizeof(emulator_sdcard)); - - tizen_sdk_data = get_tizen_sdk_data_path(); - if (!tizen_sdk_data) { - INFO("failed to get tizen-sdk-data path.\n"); - return NULL; - } - - emulator_sdcard_path = - g_malloc(strlen(tizen_sdk_data) + sizeof(emulator_sdcard) + 1); - if (!emulator_sdcard_path) { - INFO("failed to allocate memory.\n"); - return NULL; - } - - g_snprintf(emulator_sdcard_path, strlen(tizen_sdk_data) + sizeof(emulator_sdcard), - "%s%s", tizen_sdk_data, emulator_sdcard); - - g_free(tizen_sdk_data); - - TRACE("sdcard path: %s\n", emulator_sdcard_path); - return emulator_sdcard_path; -} - -static void handle_sdcard(char* readbuf) -{ - char token[] = "\n"; - char* ret = NULL; - ret = strtok(readbuf, token); - ret = strtok(NULL, token); - - if (atoi(ret) == 0) { - /* umount sdcard */ - //mloop_evcmd_usbdisk(NULL); - mloop_evcmd_sdcard(NULL); - } else if (atoi(ret) == 1) { - /* mount sdcard */ - char sdcard_img_path[256]; - char* sdcard_path = NULL; - - sdcard_path = get_emulator_sdcard_path(); - if (sdcard_path) { - g_strlcpy(sdcard_img_path, sdcard_path, sizeof(sdcard_img_path)); - - /* emulator_sdcard_img_path + sdcard img name */ - ret = strtok(NULL, token); - - g_strlcat(sdcard_img_path, ret, sizeof(sdcard_img_path)); - TRACE("sdcard path: %s\n", sdcard_img_path); - - //mloop_evcmd_usbdisk(sdcard_img_path); - mloop_evcmd_sdcard(sdcard_img_path); - - g_free(sdcard_path); - } else { - INFO("failed to get sdcard path!!\n"); - } - } else { - INFO("!!! unknown command : %s\n", ret); - } -} -#endif - -#define SDB_SERVER_PORT 26097 -static void register_sdb_server(char* readbuf, struct sockaddr_in* client_addr) -{ - int port = 0; - char token[] = "\n"; - char* ret = NULL; - char* serial = NULL; - - ret = strtok(readbuf, token); - if (ret == NULL) { - INFO("command is not found."); - return; - } - - serial = strtok(NULL, token); - if (serial == NULL) { - INFO("serial is not found."); - return; - } - - port = SDB_SERVER_PORT; - - add_sdb_client(client_addr, port, serial); -} - -#define PRESS 1 -#define RELEASE 2 -#define POWER_KEY 116 -static void wakeup_guest(void) -{ - // FIXME: Temporarily working model. - // It must be fixed as the way it works. - maru_hwkey_event(PRESS, POWER_KEY); - maru_hwkey_event(RELEASE, POWER_KEY); -} - -static void suspend_lock_state(int state) -{ - ecs_suspend_lock_state(state); -} - -static void command_handler(char* readbuf, struct sockaddr_in* client_addr) -{ - char command[RECV_BUF_SIZE]; - memset(command, '\0', sizeof(command)); - - parse_val(readbuf, 0x0a, command); - - TRACE("----------------------------------------\n"); - TRACE("command:%s\n", command); - if (strcmp(command, "2\n" ) == 0) { - notify_sdb_daemon_start(); - } else if (strcmp(command, "5\n") == 0) { - register_sdb_server(readbuf, client_addr); - } else if (strcmp(command, "6\n") == 0) { - wakeup_guest(); - } else if (strcmp(command, "7\n") == 0) { - suspend_lock_state(SUSPEND_LOCK); - } else if (strcmp(command, "8\n") == 0) { - suspend_lock_state(SUSPEND_UNLOCK); - } else { - INFO("!!! unknown command : %s\n", command); - } - TRACE("========================================\n"); -} - -static void server_process(void) -{ - int read_cnt = 0; - struct sockaddr_in client_addr; - socklen_t client_len; - char readbuf[RECV_BUF_SIZE + 1]; - - client_len = sizeof(client_addr); - - running = 1; - - while (running) { - memset(&readbuf, 0, sizeof(readbuf)); - - if (server_sock == 0) { - INFO("server_sock is closed\n"); - return; - } - read_cnt = recvfrom(server_sock, readbuf, RECV_BUF_SIZE, 0, - (struct sockaddr*) &client_addr, &client_len); - - if (read_cnt < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { -#ifdef _WIN32 - Sleep(2); -#else - usleep(2000); -#endif - continue; - } - INFO("fail to recvfrom in guest_server:%d\n", errno); - break; - } else if (read_cnt == 0) { - INFO("read_cnt is 0.\n"); - break; - } - - TRACE("================= recv =================\n"); - TRACE("read_cnt:%d\n", read_cnt); - TRACE("readbuf:%s\n", readbuf); - - command_handler(readbuf, &client_addr); - - } -} - -static void close_clients(void) -{ - qemu_mutex_lock(&mutex_clients); - GS_Client * client, *next; - - QTAILQ_FOREACH_SAFE(client, &clients, next, next) - { - QTAILQ_REMOVE(&clients, client, next); - - if (NULL != client) - { - g_free(client); - } - } - - qemu_mutex_unlock(&mutex_clients); -} - -static void close_server(void) -{ - close_clients(); -#ifdef _WIN32 - if (server_sock) { - closesocket(server_sock); - } -#else - if (server_sock) { - close(server_sock); - } -#endif - server_sock = 0; - - qemu_mutex_destroy(&mutex_clients); -} - -static void* run_guest_server(void* args) -{ - uint16_t port = svr_port; - int opt = 1; - int ret = 0; - struct sockaddr_in server_addr; - - INFO("start guest server thread.\n"); - - if ((server_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - INFO("create listen socket error:%d\n", errno); - - close_server(); - - return NULL; - } - - memset(&server_addr, '\0', sizeof(server_addr)); - server_addr.sin_family = PF_INET; - server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - server_addr.sin_port = htons(port); - - qemu_set_nonblock(server_sock); - - ret = qemu_setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - if (ret == -1) { - INFO("setsockopt SO_REUSEADDR is failed.: %d\n", errno); - close_server(); - return NULL; - } - - if (bind(server_sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { - INFO("guest server bind error: %d", errno); - - close_server(); - - return NULL; - } else { - INFO("success to bind port[127.0.0.1:%d/udp] for guest_server in host\n", port); - } - - INFO("guest server start...port:%d\n", port); - - qemu_mutex_init(&mutex_clients); - - server_process(); - - close_server(); - - return NULL; -} - -static void shutdown_guest_server(void) -{ - void *ret = NULL; - INFO("shutdown_guest_server.\n"); - - running = 0; - - ret = qemu_thread_join(&guest_thread_id); - if (ret) - INFO("guest_thread_id join failed.\n"); -} - -static void guest_server_notify_exit(Notifier *notifier, void *data) { - shutdown_guest_server(); -} -static Notifier guest_server_exit = { .notify = guest_server_notify_exit }; - -void start_guest_server(int server_port) -{ - svr_port = server_port; - qemu_thread_create(&guest_thread_id, "guest_server", run_guest_server, NULL, QEMU_THREAD_JOINABLE); - INFO("created guest server thread\n"); - - emulator_add_exit_notifier(&guest_server_exit); -} diff --git a/tizen/src/hw/maru_pm.c b/tizen/src/hw/maru_pm.c index 9bb2b68ed8..abaf96ccd9 100644 --- a/tizen/src/hw/maru_pm.c +++ b/tizen/src/hw/maru_pm.c @@ -31,7 +31,7 @@ #include "sysemu/sysemu.h" #include "debug_ch.h" -#include "guest_server.h" +#include "sdb_noti_server.h" /* define debug channel */ MULTI_DEBUG_CHANNEL(tizen, maru_pm); diff --git a/tizen/src/sdb_noti_server.c b/tizen/src/sdb_noti_server.c new file mode 100644 index 0000000000..252b7709a1 --- /dev/null +++ b/tizen/src/sdb_noti_server.c @@ -0,0 +1,430 @@ +/* + * Emulator SDB Notification Server + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: + * Jinhyung choi + * MunKyu Im + * Sangho Park + * YeongKyoon Lee + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include "qemu/sockets.h" + +#include "hw/maru_virtio_hwkey.h" +#include "hw/maru_pm.h" +#include "skin/maruskin_server.h" +#include "ecs/ecs.h" + +#include "emulator.h" +#include "debug_ch.h" +#include "sdb_noti_server.h" + +MULTI_DEBUG_CHANNEL(qemu, sdb_noti); + +#define RECV_BUF_SIZE 32 + +typedef struct SDB_Noti_Server { + int server_fd; + GIOChannel *server_chan; + guint server_tag; +} SDB_Noti_Server; + +typedef struct SDB_Client { + int port; + struct sockaddr_in addr; + char serial[RECV_BUF_SIZE]; + + QTAILQ_ENTRY(SDB_Client) next; +} SDB_Client; + +static QTAILQ_HEAD(SDB_ClientHead, SDB_Client) +clients = QTAILQ_HEAD_INITIALIZER(clients); + +static SDB_Noti_Server *current_server; +static QemuMutex mutex_clients; + +static void remove_sdb_client(SDB_Client* client) +{ + if (client == NULL) { + return; + } + + qemu_mutex_lock(&mutex_clients); + + QTAILQ_REMOVE(&clients, client, next); + + qemu_mutex_unlock(&mutex_clients); + + g_free(client); +} + +static void send_to_sdb_client(SDB_Client* client, int state) +{ + struct sockaddr_in sock_addr; + int s, slen = sizeof(sock_addr); + int serial_len = 0; + char buf [32]; + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){ + INFO("socket creation error! %d\n", errno); + return; + } + + memset(&sock_addr, 0, sizeof(sock_addr)); + + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = htons(client->port); + sock_addr.sin_addr = (client->addr).sin_addr; + + if (connect(s, (struct sockaddr*)&sock_addr, slen) == -1) { + INFO("connect error! remove this client.\n"); + remove_sdb_client(client); + close(s); + return; + } + + memset(buf, 0, sizeof(buf)); + + serial_len = strlen(client->serial); + + // send message "[4 digit message length]host:sync:emulator-26101:[0|1]" + sprintf(buf, "%04xhost:sync:%s:%01d", (serial_len + 12), client->serial, state); + + INFO("send %s to client %s\n", buf, inet_ntoa(client->addr.sin_addr)); + + if (send(s, buf, sizeof(buf), 0) == -1) + { + INFO("send error! remove this client.\n"); + remove_sdb_client(client); + } + + close(s); +} + +void notify_all_sdb_clients(int state) +{ + qemu_mutex_lock(&mutex_clients); + SDB_Client *client, *next; + + QTAILQ_FOREACH_SAFE(client, &clients, next, next) + { + send_to_sdb_client(client, state); + } + qemu_mutex_unlock(&mutex_clients); + +} + +static void add_sdb_client(struct sockaddr_in* addr, int port, const char* serial) +{ + SDB_Client *cli = NULL; + SDB_Client *client = NULL, *next; + + if (addr == NULL) { + INFO("SDB_Client client's address is EMPTY.\n"); + return; + } else if (serial == NULL || strlen(serial) <= 0) { + INFO("SDB_Client client's serial is EMPTY.\n"); + return; + } else if (strlen(serial) > RECV_BUF_SIZE) { + INFO("SDB_Client client's serial is too long. %s\n", serial); + return; + } + + qemu_mutex_lock(&mutex_clients); + QTAILQ_FOREACH_SAFE(cli, &clients, next, next) + { + if (!strcmp(serial, cli->serial) && !strcmp(inet_ntoa(addr->sin_addr), inet_ntoa((cli->addr).sin_addr))) { + INFO("Client cannot be duplicated.\n"); + qemu_mutex_unlock(&mutex_clients); + return; + } + } + qemu_mutex_unlock(&mutex_clients); + + client = g_malloc0(sizeof(SDB_Client)); + if (NULL == client) { + INFO("SDB_Client allocation failed.\n"); + return; + } + + memcpy(&client->addr, addr, sizeof(struct sockaddr_in)); + client->port = port; + strcpy(client->serial, serial); + + qemu_mutex_lock(&mutex_clients); + + QTAILQ_INSERT_TAIL(&clients, client, next); + + qemu_mutex_unlock(&mutex_clients); + + INFO("Added new sdb client. ip: %s, port: %d, serial: %s\n", inet_ntoa((client->addr).sin_addr), client->port, client->serial); + + send_to_sdb_client(client, runstate_check(RUN_STATE_SUSPENDED)); +} + +static int parse_val(char* buff, unsigned char data, char* parsbuf) +{ + int count = 0; + + while (1) { + if (count > 12) { + return -1; + } + + if (buff[count] == data) { + count++; + strncpy(parsbuf, buff, count); + return count; + } + + count++; + } + + return 0; +} + +#define SDB_SERVER_PORT 26097 +static void register_sdb_server(char* readbuf, struct sockaddr_in* client_addr) +{ + int port = 0; + char token[] = "\n"; + char* ret = NULL; + char* serial = NULL; + + ret = strtok(readbuf, token); + if (ret == NULL) { + INFO("command is not found."); + return; + } + + serial = strtok(NULL, token); + if (serial == NULL) { + INFO("serial is not found."); + return; + } + + port = SDB_SERVER_PORT; + + add_sdb_client(client_addr, port, serial); +} + +#define PRESS 1 +#define RELEASE 2 +#define POWER_KEY 116 +static void wakeup_guest(void) +{ + // FIXME: Temporarily working model. + // It must be fixed as the way it works. + maru_hwkey_event(PRESS, POWER_KEY); + maru_hwkey_event(RELEASE, POWER_KEY); +} + +static void suspend_lock_state(int state) +{ + ecs_suspend_lock_state(state); +} + +static void command_handler(char* readbuf, struct sockaddr_in* client_addr) +{ + char command[RECV_BUF_SIZE]; + memset(command, '\0', sizeof(command)); + + parse_val(readbuf, 0x0a, command); + + TRACE("----------------------------------------\n"); + TRACE("command:%s\n", command); + if (strcmp(command, "2\n" ) == 0) { + notify_sdb_daemon_start(); + } else if (strcmp(command, "5\n") == 0) { + register_sdb_server(readbuf, client_addr); + } else if (strcmp(command, "6\n") == 0) { + wakeup_guest(); + } else if (strcmp(command, "7\n") == 0) { + suspend_lock_state(SUSPEND_LOCK); + } else if (strcmp(command, "8\n") == 0) { + suspend_lock_state(SUSPEND_UNLOCK); + } else { + INFO("!!! unknown command : %s\n", command); + } + TRACE("========================================\n"); +} + +static void close_clients(void) +{ + qemu_mutex_lock(&mutex_clients); + SDB_Client * client, *next; + + QTAILQ_FOREACH_SAFE(client, &clients, next, next) + { + QTAILQ_REMOVE(&clients, client, next); + + if (NULL != client) + { + g_free(client); + } + } + + qemu_mutex_unlock(&mutex_clients); +} + +static void close_server(void) +{ + if (current_server == NULL) { + return; + } + + close_clients(); + + if (current_server->server_fd > 0) { + if (current_server->server_tag) { + g_source_remove(current_server->server_tag); + current_server->server_tag = 0; + } + if (current_server->server_chan) { + g_io_channel_unref(current_server->server_chan); + } + closesocket(current_server->server_fd); + } + + g_free(current_server); + + qemu_mutex_destroy(&mutex_clients); +} + +static gboolean sdb_noti_read(GIOChannel *channel, GIOCondition cond, void *opaque) +{ + int recv_cnt = 0; + struct sockaddr_in client_addr; + socklen_t client_len; + char readbuf[RECV_BUF_SIZE + 1]; + SDB_Noti_Server *server = opaque; + + memset(&readbuf, 0, sizeof(readbuf)); + + recv_cnt = recvfrom(server->server_fd, readbuf, RECV_BUF_SIZE, 0, + (struct sockaddr*) &client_addr, &client_len); + + if (recv_cnt > 0) { + command_handler((char*)readbuf, &client_addr); + } else if (recv_cnt == 0) { + INFO("noti server recvfrom returned 0.\n"); + } else { +#ifdef _WIN32 + errno = WSAGetLastError(); +#endif + TRACE("recvfrom error case (it can be from non-blocking socket): %d", errno); + } + + return TRUE; +} + +static int create_UDP_server(SDB_Noti_Server *server, int port) +{ + struct sockaddr_in server_addr; + int opt = 1; + + if ((server->server_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + INFO("create listen socket error:%d\n", errno); + return -1; + } + + memset(&server_addr, '\0', sizeof(server_addr)); + server_addr.sin_family = PF_INET; + server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + server_addr.sin_port = htons(port); + + qemu_set_nonblock(server->server_fd); + + if (qemu_setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) { + INFO("setsockopt SO_REUSEADDR is failed.: %d\n", errno); + return -1; + } + + if (bind(server->server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { + INFO("sdb noti server bind error: %d", errno); + return -1; + } + + return 0; +} + +static GIOChannel *io_channel_from_socket(int fd) +{ + GIOChannel *chan; + + if (fd == -1) { + return NULL; + } + +#ifdef _WIN32 + chan = g_io_channel_win32_new_socket(fd); +#else + chan = g_io_channel_unix_new(fd); +#endif + + g_io_channel_set_encoding(chan, NULL, NULL); + g_io_channel_set_buffered(chan, FALSE); + + return chan; +} + +static void sdb_noti_server_notify_exit(Notifier *notifier, void *data) +{ + INFO("shutdown sdb notification server.\n"); + close_server(); +} + +static Notifier sdb_noti_server_exit = { .notify = sdb_noti_server_notify_exit }; + +void start_sdb_noti_server(int server_port) +{ + SDB_Noti_Server *server; + int ret; + + INFO("start sdb noti server thread.\n"); + + server = g_malloc0(sizeof(SDB_Noti_Server)); + if (server == NULL) { + INFO("SDB Notification server allocation is failed.\n"); + return; + } + + ret = create_UDP_server(server, server_port); + if (ret < 0) { + INFO("failed to create UDP server\n"); + close_server(); + return; + } + + server->server_chan = io_channel_from_socket(server->server_fd); + server->server_tag = g_io_add_watch(server->server_chan, G_IO_IN, sdb_noti_read, server); + + current_server = server; + + qemu_mutex_init(&mutex_clients); + + INFO("success to bind port[127.0.0.1:%d/udp] for sdb noti server in host \n", server_port); + + emulator_add_exit_notifier(&sdb_noti_server_exit); +} + diff --git a/tizen/src/guest_server.h b/tizen/src/sdb_noti_server.h similarity index 68% rename from tizen/src/guest_server.h rename to tizen/src/sdb_noti_server.h index 2f0404d885..9aaf7b3bfb 100644 --- a/tizen/src/guest_server.h +++ b/tizen/src/sdb_noti_server.h @@ -1,13 +1,13 @@ /* + * Emulator SDB Notification Server * - * - * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: - * JiHye Kim - * GiWoong Kim - * YeongKyoon Lee - * Hyunjun Son + * Jinhyung choi + * MunKyu Im + * Sangho Park + * YeongKyoon Lee * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,16 +28,13 @@ * */ +#ifndef SDB_NOTI_SERVER_H_ +#define SDB_NOTI_SERVER_H_ -#ifndef GUEST_SERVER_H_ -#define GUEST_SERVER_H_ - -#include - -void start_guest_server( int server_port ); +void start_sdb_noti_server(int server_port); #define STATE_RUNNING 0 #define STATE_SUSPEND 1 void notify_all_sdb_clients(int state); -#endif /* GUEST_SERVER_H_ */ +#endif -- 2.34.1