4 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
7 * MunKyu Im <munkyu.im@samsung.com>
8 * Jinhyung Choi <jinh0.choi@samsung.com>
9 * SeokYeon Hwnag <syeon.hwang@samsung.com>
10 * Sangho Park <sangho.p@samsung.com>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 #include "net_helper.h"
33 #include "qemu/osdep.h"
34 #include "qemu/sockets.h"
35 #include "net/slirp.h"
36 #include "block/nbd.h"
37 #include "qemu/error-report.h"
40 #include "emulator_common.h"
41 #include "emul_state.h"
43 #include "hw/virtio/maru_virtio_input.h"
44 #include "hw/maru_pm.h"
46 #include "new_debug_ch.h"
48 DECLARE_DEBUG_CHANNEL(net_helper);
52 #define MAX_USER_NAME_LEN 36
54 int emul_vm_base_socket;
55 static bool sdb_daemon_is_initialized = false;
56 static QemuThread thread_id;
58 int inet_strtoip(const char* str, uint32_t *ip)
62 if (sscanf(str, "%d.%d.%d.%d", &comp[0], &comp[1], &comp[2], &comp[3]) != 4)
65 if ((unsigned)comp[0] >= 256 ||
66 (unsigned)comp[1] >= 256 ||
67 (unsigned)comp[2] >= 256 ||
68 (unsigned)comp[3] >= 256)
71 *ip = (uint32_t)((comp[0] << 24) | (comp[1] << 16) |
72 (comp[2] << 8) | comp[3]);
76 int check_port_bind_listen(uint32_t port)
78 struct sockaddr_in addr;
80 addr.sin_family = AF_INET;
81 addr.sin_port = htons(port);
82 addr.sin_addr.s_addr = INADDR_ANY;
84 ret = qemu_socket(PF_INET, SOCK_STREAM, 0);
86 LOG_SEVERE("socket creation failed.\n");
90 qemu_set_nonblock(ret);
92 if (socket_set_fast_reuse(ret) != 0) {
93 LOG_SEVERE("It cannot be reach here.\n");
98 if (bind(ret, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
99 LOG_INFO("bind failed for port: %d, errno: %d\n", port, errno);
104 if (listen(ret, 1) != 0) {
105 LOG_SEVERE("listen failed :%s-%d\n", strerror(errno), errno);
113 static int prepare_network_port(uint32_t base_port)
117 /* no need to redir if network is tap */
118 if (!is_netclient_tap_attached()) {
119 if (!hostfwd_try_add(0, NULL, base_port + SDB_TCP_INDEX,
120 NULL, SDB_GUEST_PORT)) {
121 LOG_INFO("TCP port %"PRIu32" is aleady occupied",
122 base_port + SDB_TCP_INDEX);
127 if (!hostfwd_try_add(0, NULL, base_port + GDB_TCP_INDEX,
128 NULL, GDB_GUEST_PORT)) {
129 LOG_INFO("TCP port %"PRIu32" is aleady occupied",
130 base_port + GDB_TCP_INDEX);
131 hostfwd_try_remove(0, NULL, base_port + SDB_TCP_INDEX);
137 if ((ret = check_port_bind_listen(base_port + ECS_TCP_INDEX)) < 0) {
138 LOG_INFO("TCP port %"PRIu32" is aleady occupied",
139 base_port + ECS_TCP_INDEX);
141 if (!is_netclient_tap_attached()) {
142 hostfwd_try_remove(0, NULL, base_port + SDB_TCP_INDEX);
143 hostfwd_try_remove(0, NULL, base_port + GDB_TCP_INDEX);
151 // save ecs socket fd as global variable
152 // FIXME: should not use global variable.
153 emul_vm_base_socket = ret;
158 static void start_sdb_noti_server(int server_port);
160 void init_sdb_and_vm_base_port(void)
164 for (port = START_VM_BASE_PORT ; port < END_VM_BASE_PORT; port += 10) {
165 if (prepare_network_port(port) < 0) {
172 if (port >= END_VM_BASE_PORT) {
173 error_report("It seems too many emulator instances are "
174 "running on this machine. Aborting.");
178 LOG_INFO("Emulator base port is %"PRIu32".\n", port);
180 start_sdb_noti_server(port + SDB_UDP_NOTI_PORT_INDEX);
186 * SDB Notification server
189 #define RECV_BUF_SIZE 32
190 typedef struct SDB_Noti_Server {
192 GIOChannel *server_chan;
196 typedef struct SDB_Client {
198 struct sockaddr_in addr;
199 char serial[RECV_BUF_SIZE];
201 QTAILQ_ENTRY(SDB_Client) next;
204 static QTAILQ_HEAD(SDB_ClientHead, SDB_Client)
205 clients = QTAILQ_HEAD_INITIALIZER(clients);
207 static SDB_Noti_Server *current_server;
208 static QemuMutex mutex_clients;
209 static QemuMutex mutex_request;
211 static void remove_sdb_client(SDB_Client* client)
213 if (client == NULL) {
217 qemu_mutex_lock(&mutex_clients);
219 QTAILQ_REMOVE(&clients, client, next);
221 qemu_mutex_unlock(&mutex_clients);
226 static void send_to_sdb_client(SDB_Client* client, int state)
228 struct sockaddr_in sock_addr;
229 int s, slen = sizeof(sock_addr);
233 if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) == -1){
234 LOG_INFO("socket creation error! %d\n", errno);
238 memset(&sock_addr, 0, sizeof(sock_addr));
240 sock_addr.sin_family = AF_INET;
241 sock_addr.sin_port = htons(client->port);
242 sock_addr.sin_addr = (client->addr).sin_addr;
244 if (connect(s, (struct sockaddr*)&sock_addr, slen) == -1) {
245 LOG_INFO("connect error! remove this client.\n");
246 remove_sdb_client(client);
251 memset(buf, 0, sizeof(buf));
253 serial_len = strlen(client->serial);
255 // send message "[4 digit message length]host:sync:emulator-26101:[0|1]"
256 sprintf(buf, "%04xhost:sync:%s:%01d", (serial_len + 12), client->serial, state);
258 LOG_INFO("send %s to client %s\n", buf, inet_ntoa(client->addr.sin_addr));
260 if (send(s, buf, sizeof(buf), 0) == -1)
262 LOG_INFO("send error! remove this client.\n");
263 remove_sdb_client(client);
269 void notify_all_sdb_clients(int state)
271 qemu_mutex_lock(&mutex_clients);
272 SDB_Client *client, *next;
274 QTAILQ_FOREACH_SAFE(client, &clients, next, next)
276 send_to_sdb_client(client, state);
278 qemu_mutex_unlock(&mutex_clients);
282 static void add_sdb_client(struct sockaddr_in* addr, int port, const char* serial)
284 SDB_Client *cli = NULL;
285 SDB_Client *client = NULL, *next;
288 LOG_INFO("SDB_Client client's address is EMPTY.\n");
290 } else if (serial == NULL || strlen(serial) <= 0) {
291 LOG_INFO("SDB_Client client's serial is EMPTY.\n");
293 } else if (strlen(serial) > RECV_BUF_SIZE) {
294 LOG_INFO("SDB_Client client's serial is too long. %s\n", serial);
298 qemu_mutex_lock(&mutex_clients);
299 QTAILQ_FOREACH_SAFE(cli, &clients, next, next)
301 if (!strcmp(serial, cli->serial) && !strcmp(inet_ntoa(addr->sin_addr), inet_ntoa((cli->addr).sin_addr))) {
302 LOG_INFO("Client cannot be duplicated.\n");
303 qemu_mutex_unlock(&mutex_clients);
307 qemu_mutex_unlock(&mutex_clients);
309 client = g_malloc0(sizeof(SDB_Client));
310 if (NULL == client) {
311 LOG_INFO("SDB_Client allocation failed.\n");
315 memcpy(&client->addr, addr, sizeof(struct sockaddr_in));
317 strcpy(client->serial, serial);
319 qemu_mutex_lock(&mutex_clients);
321 QTAILQ_INSERT_TAIL(&clients, client, next);
323 qemu_mutex_unlock(&mutex_clients);
325 LOG_INFO("Added new sdb client. ip: %s, port: %d, serial: %s\n", inet_ntoa((client->addr).sin_addr), client->port, client->serial);
327 send_to_sdb_client(client, runstate_check(RUN_STATE_SUSPENDED));
330 static int parse_val(char* buff, unsigned char data, char* parsbuf)
339 if (buff[count] == data) {
341 strncpy(parsbuf, buff, count);
351 #define SDB_SERVER_PORT 26097
352 static void register_sdb_server(char* readbuf, struct sockaddr_in* client_addr)
359 ret = strtok(readbuf, token);
361 LOG_INFO("command is not found.");
365 serial = strtok(NULL, token);
366 if (serial == NULL) {
367 LOG_INFO("serial is not found.");
371 port = SDB_SERVER_PORT;
373 add_sdb_client(client_addr, port, serial);
378 #define POWER_KEY 116
379 static void wakeup_guest(void)
381 // FIXME: Temporarily working model.
382 // It must be fixed as the way it works.
383 maru_hwkey_event(PRESS, POWER_KEY);
384 maru_hwkey_event(RELEASE, POWER_KEY);
387 static void suspend_lock_state(int state)
389 ecs_suspend_lock_state(state);
392 static void *get_user_home_path(void *args)
395 char user_name[MAX_USER_NAME_LEN] = { 0, } ;
397 int sleep_time = 500; // msec
399 const char *sdb_path = "../../../../../tools/sdb";
401 const char *sdb_path = "..\\..\\..\\..\\..\\tools\\sdb.exe";
403 const char *bin_dir = get_bin_path();
405 qemu_mutex_lock(&mutex_request);
407 if (get_platform_default_home()) {
411 char *cmd_root_off = g_strdup_printf("\"%s%s\" -s emulator-%d root off 2> /dev/null",
412 bin_dir, sdb_path, get_vm_device_serial_number());
413 char *cmd_get_home = g_strdup_printf("\"%s%s\" -s emulator-%d shell id -un 2> /dev/null",
414 bin_dir, sdb_path, get_vm_device_serial_number());
416 char *cmd_root_off = g_strdup_printf("\"%s%s\" -s emulator-%d root off 2> NUL",
417 bin_dir, sdb_path, get_vm_device_serial_number());
418 char *cmd_get_home = g_strdup_printf("\"%s%s\" -s emulator-%d shell id -un 2> NUL",
419 bin_dir, sdb_path, get_vm_device_serial_number());
421 //FIXME: (sdb) cannot check sdb root status
422 fp = popen(cmd_root_off, "r");
424 LOG_WARNING("Failed to run command\n");
425 g_free(cmd_root_off);
428 g_free(cmd_root_off);
431 if (trial >= MAX_TRIAL) {
439 usleep(sleep_time * 1000);
441 fp = popen(cmd_get_home, "r");
443 LOG_WARNING("Failed to run command\n");
447 if (fgets(user_name, sizeof(user_name), fp)) {
448 g_strstrip(user_name);
449 if (strlen(user_name) > 0) {
450 char *path = g_strdup_printf("/home/%s/", user_name);
451 set_platform_default_home(path);
460 g_free(cmd_get_home);
462 if (!get_platform_default_home()) {
463 set_platform_default_home("/tmp/");
466 LOG_INFO("platform_default_user_home: %s\n", get_platform_default_home());
468 qemu_mutex_unlock(&mutex_request);
473 static void command_handler(char* readbuf, struct sockaddr_in* client_addr)
475 char command[RECV_BUF_SIZE];
476 memset(command, '\0', sizeof(command));
478 parse_val(readbuf, 0x0a, command);
480 LOG_TRACE("----------------------------------------\n");
481 LOG_TRACE("command:%s\n", command);
482 if (strcmp(command, "2\n" ) == 0) {
483 sdb_daemon_is_initialized = true;
484 if (!get_platform_default_home()) {
485 qemu_thread_create(&thread_id, "get_platform_default_home",
486 get_user_home_path, NULL, QEMU_THREAD_DETACHED);
488 } else if (strcmp(command, "5\n") == 0) {
489 register_sdb_server(readbuf, client_addr);
490 set_sdb_connection(true);
491 } else if (strcmp(command, "6\n") == 0) {
493 } else if (strcmp(command, "7\n") == 0) {
494 suspend_lock_state(SUSPEND_LOCK);
495 } else if (strcmp(command, "8\n") == 0) {
496 suspend_lock_state(SUSPEND_UNLOCK);
498 LOG_INFO("!!! unknown command : %s\n", command);
500 LOG_TRACE("========================================\n");
503 static void close_clients(void)
505 qemu_mutex_lock(&mutex_clients);
506 SDB_Client * client, *next;
508 QTAILQ_FOREACH_SAFE(client, &clients, next, next)
510 QTAILQ_REMOVE(&clients, client, next);
518 qemu_mutex_unlock(&mutex_clients);
521 static void close_server(void)
523 if (current_server == NULL) {
529 if (current_server->server_fd > 0) {
530 if (current_server->server_tag) {
531 g_source_remove(current_server->server_tag);
532 current_server->server_tag = 0;
534 if (current_server->server_chan) {
535 g_io_channel_unref(current_server->server_chan);
537 closesocket(current_server->server_fd);
540 g_free(current_server);
542 qemu_mutex_destroy(&mutex_clients);
545 static gboolean sdb_noti_read(GIOChannel *channel, GIOCondition cond, void *opaque)
548 struct sockaddr_in client_addr;
549 socklen_t client_len = sizeof(client_addr);
550 char readbuf[RECV_BUF_SIZE + 1];
551 SDB_Noti_Server *server = opaque;
553 memset(&readbuf, 0, sizeof(readbuf));
555 recv_cnt = recvfrom(server->server_fd, readbuf, RECV_BUF_SIZE, 0,
556 (struct sockaddr*) &client_addr, &client_len);
559 command_handler((char*)readbuf, &client_addr);
560 } else if (recv_cnt == 0) {
561 LOG_INFO("noti server recvfrom returned 0.\n");
564 errno = WSAGetLastError();
566 LOG_TRACE("recvfrom error case (it can be from non-blocking socket): %d", errno);
572 static int create_UDP_server(SDB_Noti_Server *server, int port)
574 struct sockaddr_in server_addr;
577 if ((server->server_fd = qemu_socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
578 LOG_INFO("create listen socket error:%d\n", errno);
582 memset(&server_addr, '\0', sizeof(server_addr));
583 server_addr.sin_family = PF_INET;
584 server_addr.sin_addr.s_addr = INADDR_ANY;
585 server_addr.sin_port = htons(port);
587 qemu_set_nonblock(server->server_fd);
589 if (qemu_setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
590 LOG_INFO("setsockopt SO_REUSEADDR is failed.: %d\n", errno);
594 if (bind(server->server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
595 LOG_INFO("sdb noti server bind error: %d", errno);
602 static GIOChannel *io_channel_from_socket(int fd)
611 chan = g_io_channel_win32_new_socket(fd);
613 chan = g_io_channel_unix_new(fd);
616 g_io_channel_set_encoding(chan, NULL, NULL);
617 g_io_channel_set_buffered(chan, FALSE);
622 static void sdb_noti_server_notify_exit(Notifier *notifier, void *data)
624 LOG_INFO("shutdown sdb notification server.\n");
628 static Notifier sdb_noti_server_exit = { .notify = sdb_noti_server_notify_exit };
630 static void start_sdb_noti_server(int server_port)
632 SDB_Noti_Server *server;
635 LOG_INFO("start sdb noti server thread.\n");
637 server = g_malloc0(sizeof(SDB_Noti_Server));
638 if (server == NULL) {
639 LOG_INFO("SDB Notification server allocation is failed.\n");
643 ret = create_UDP_server(server, server_port);
645 LOG_INFO("failed to create UDP server\n");
650 qemu_mutex_init(&mutex_clients);
651 qemu_mutex_init(&mutex_request);
653 server->server_chan = io_channel_from_socket(server->server_fd);
654 server->server_tag = g_io_add_watch(server->server_chan, G_IO_IN, sdb_noti_read, server);
656 current_server = server;
658 LOG_INFO("success to bind port[127.0.0.1:%d/udp] for sdb noti server in host \n", server_port);
660 emulator_add_exit_notifier(&sdb_noti_server_exit);
663 bool is_sdb_daemon_initialized(void)
665 return sdb_daemon_is_initialized;