static int async_ipc_estream_func(estream_t *e, u8 *data, int len) { async_ipc_t *aipc = estream_get_data(e); async_ipc_read_op_t *op; if (!len) return 0; /* Finished writing */ if (!(op = aipc->queue)) { rg_error(LERR, "Async IPC: Received %d unexpected bytes", len); goto Error; } switch (op->state) { case AIPC_WAIT_FOR_N: case AIPC_WAIT_FOR_N_AND_DATA: if (len != sizeof(*op->n)) { rg_error(LERR, "Async IPC: Received %d while reading N", len); goto Error; } /* Avoid possible misalignment of data */ memcpy(op->n, data, sizeof(*op->n)); *op->n = ntohl(*op->n); if (op->state == AIPC_WAIT_FOR_N_AND_DATA && *op->n) { op->state = AIPC_WAIT_FOR_DATA; estream_read(aipc->e, *op->n); } else async_ipc_process_op(aipc); break; case AIPC_WAIT_FOR_DATA: if (len != *op->n) { rg_error(LERR, "Async IPC: Expected %d bytes, received %d", *op->n, len); goto Error; } *op->data = memdup_e(data, len); if (op->is_string) { /* '\0' should be sent by the other side, we want to be on the * safe side */ (*op->data)[len-1] = 0; } async_ipc_process_op(aipc); break; } return 0; Error: async_ipc_notify(aipc, -1); return 0; }
int gpl_sys_rg_chrdev_open(int type, int mode) { int fd = open("/dev/rg_chrdev", mode, 0); if (fd < 0) { rg_error(LERR, "Cannot open /dev/rg_chrdev %d %m", type); return fd; } if (ioctl(fd, RG_IOCTL_SIOCSETRGCHRDEVTYPE, type)) return rg_error(LERR, "Cannot open /dev/rg_chrdev %d %m", type); return fd; }
int ipc_wait_for_server(u16 port) { struct sockaddr_in sa; int fd; MZERO(sa); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr("127.0.0.1"); sa.sin_port = port; if ((fd = sock_socket(SOCK_STREAM, 0, 0)) < 0) { rg_error(LERR, "failed creating socket"); return -1; } /* Try to connect to server infinitely */ while (1) { if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) >= 0) break; /* Sleep for 10ms before trying again */ usleep(10000); } /* Once the server accepts the connection, it tries to send the client a * sync message. It will fail if we close the socket now. So we keep the * socket open until a sync is received, to keep the server happy. */ ipc_client_sync(fd); socket_close(fd); return 0; }
void *memdup_log(rg_error_level_t severity, void *ptr, int len) { void *dst; if (!(dst = memdup(ptr, len))) rg_error(severity, "memdup(buf %p len %d) failed", ptr, len); return dst; }
void *zalloc_log(rg_error_level_t level, size_t size) { void *mem; if (!(mem = zalloc(size))) rg_error(level, "zalloc_e(%d): failed", size); return mem; }
void *strdup_log(rg_error_level_t level, char *s) { char *str; if (!(str = strdup(s))) rg_error(level, "strdup() failed"); return str; }
void *realloc_log(rg_error_level_t level, void *p, size_t size) { void *mem; if (!(mem = realloc(p, size))) rg_error(level, "realloc_e(%zd): failed", size); return mem; }
void *malloc_log(rg_error_level_t level, size_t size) { void *mem; mem = malloc(size); if (!mem) rg_error(level, "malloc_e(%zd): failed", size); return mem; }
/* normally should be called with src_ip==0 and src_port==0 */ int sock_socket(int type, u32 src_ip, u16 src_port) { int sock = -1; struct sockaddr_in sa; if ((sock = socket(AF_INET, type, 0))<0) return rg_error(LERR, "sock_socket: failed socket()"); MZERO(sa); sa.sin_family = AF_INET; sa.sin_addr.s_addr = src_ip; sa.sin_port = src_port; if (src_port) { int opt = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt))<0) { rg_error(LERR, "sock_socket: failed setsockopt(SO_REUSEADDR)"); goto Error; } if ((bind(sock, (struct sockaddr *)&sa, sizeof(sa)))<0) { rg_error(LERR, "sock_socket: failed bind(): %s", strerror(errno)); goto Error; } } else { if ((bind(sock, (struct sockaddr *)&sa, sizeof(sa)))<0) { rg_error(LERR, "sock_socket: failed bind()"); goto Error; } } rg_error(LDEBUG, "sock_socket: created fd %d for ip %s port %d", sock, inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); return sock; Error: if (sock>=0) close(sock); return -1; }
int ipc_accept(int server_fd) { int fd; if ((fd = bio_accept(server_fd)) < 0) { rg_error(LERR, "%d: failed ipc accept %m", server_fd); return -1; } if (ipc_server_sync(fd)) { rg_error(LERR, "%d: failed ipc accept sync", server_fd); goto Error; } return fd; Error: socket_close(fd); return -1; }
static int __ipc_connect_ip(u16 port, u32 addr, int quiet) { struct sockaddr_in sa; int fd = -1; while (1) { if ((fd = sock_socket(SOCK_STREAM, 0, 0)) < 0) return -1; MZERO(sa); sa.sin_family = AF_INET; sa.sin_addr.s_addr = addr; sa.sin_port = port; if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { socket_close(fd); if (!quiet) rg_error(LERR, "failed ipc connect %m"); return -1; } /* Linux 2.4 kernel has a bug with localhost connections. * After the server calls listen(), then the client calls * connect() and returns with success immediately, before * the server calls accept()! * Therefore, a SYNC_STR command is used to make sure the connect * succeeded. * This has not been tested on Linux 2.2 whether it too has * this bug. It probably does not exist on VxWorks, since VxWorks * TCP/IP stack is completely different (its BSD based). */ if (!ipc_client_sync(fd)) break; socket_close(fd); if (!quiet) rg_error(LWARN, "failed ipc connect sync - retrying"); sys_sleep(1); } return fd; }
void *realloc_log(rg_error_level_t level, void *p, size_t size) { void *mem; /* uClibc crashes on realloc(p, 0) */ if (!size) size = 4; if (!(mem = realloc(p, size))) rg_error(level, "realloc_e(%d): failed", size); return mem; }
static void async_ipc_estream_closed(void *context) { async_ipc_t *aipc = context; event_timer_del(async_ipc_estream_timed_out, aipc); aipc->e = NULL; if (aipc->cb) { rg_error(LERR, "Async IPC: Peer closed connection"); async_ipc_notify(aipc, -1); } }
int snprintf_l(char *str, size_t size, const char *format, ...) { int retval; va_list ap; va_start(ap, format); retval = vsnprintf(str, size, format, ap); if (retval<0) rg_error(LERR, "String '%s' truncated", str); va_end(ap); return retval; }
void *malloc_log(rg_error_level_t level, size_t size) { void *mem; /* uClibc crashes on malloc(0) */ if (!size) size = 4; mem = malloc(size); if (!mem) rg_error(level, "malloc_e(%d): failed", size); return mem; }
static int async_ipc_connected(estream_t *e, int connected) { async_ipc_t *aipc = estream_get_data(e); if (!connected) { rg_error(LERR, "Async IPC: Could not connect"); async_ipc_notify(aipc, -1); return 0; } estream_set_func(e, async_ipc_estream_func); async_ipc_read_start(aipc); return 0; }
static void rg_reboot(void) { rg_error(LINFO, "rebooting!"); #ifdef HAVE_KILL /* signal the init process (openrg or init) to reboot. */ kill(1, SIGINT); #else /* This code generates three types of exception: * division by 0 - handled by FPU/Emulator, * unaligned access (float at wrong alignment) - for non-MMU out there * segmentation - 1 is not legal at most MMU platforms. */ *(float *)1 = 1 / 0.0; #endif }
int ipc_server_sync(int fd) { char *sync = NULL; int rc = -1; if (!(sync = ipc_string_read(fd)) || strcmp(sync, SYNC_STR)) goto Exit; if (ipc_string_write(fd, SYNC_STR)) goto Exit; rc = 0; Exit: if (rc) rg_error(LERR, "%d: failed ipc server sync", fd); nfree(sync); return rc; }
int ipc_listen_ip(u16 port, u32 addr) { int fd; if ((fd = sock_socket(SOCK_STREAM, addr, port)) < 0) return -1; /* 5 is a big enough queue length */ if (listen(fd, 5) < 0) { rg_error(LERR, "failed ipc listen %m"); goto Error; } return fd; Error: socket_close(fd); return -1; }
static void process_sync(async_ipc_t *aipc) { if ((aipc->n != sizeof(RG_IPC_SYNC_STR) || strcmp(aipc->sync, RG_IPC_SYNC_STR))) { rg_error(LERR, "Async IPC: Bad sync"); async_ipc_notify(aipc, -1); return; } aipc->got_sync = 1; if (aipc->closing) { /* We got the sync upon end of message */ async_ipc_notify(aipc, 0); async_ipc_free(aipc); } else async_ipc_read_start(aipc); }
void rg_error_init(int _reboot_on_exit, int _reboot_on_panic, int strace, char *process, rg_error_level_t console_level, int (*_main_addr)(int, char *[]), const char *_main_name) { if (inited) rg_error(LEXIT, "rg_error_init: already inited"); inited = 1; if (strace) strace_init(); if (process) { strncpy(proc_name, process, MAX_PROC_NAME); proc_name[MAX_PROC_NAME-1] = 0; } else strcpy(proc_name, get_proc_name()); rg_error_console_level = console_level; main_addr = _main_addr; main_name = _main_name; reboot_on_exit = _reboot_on_exit; reboot_on_panic = _reboot_on_panic; }