--- libaitio/src/sock.c 2013/11/21 18:59:50 1.4.4.6 +++ libaitio/src/sock.c 2013/11/22 09:24:58 1.4.4.9 @@ -3,7 +3,7 @@ * by Michael Pounov * * $Author: misho $ -* $Id: sock.c,v 1.4.4.6 2013/11/21 18:59:50 misho Exp $ +* $Id: sock.c,v 1.4.4.9 2013/11/22 09:24:58 misho Exp $ * ************************************************************************** The ELWIX and AITNET software is distributed under the following @@ -57,6 +57,10 @@ io_closeClient(sched_task_t *task) TAILQ_REMOVE(&s->sock_cli, cli, cli_node); pthread_mutex_unlock(&s->sock_mtx); + schedCancelby(s->sock_root, taskTIMER, CRITERIA_DATLEN, + (void*) cli->cli_fd, NULL); + schedCancelby(s->sock_root, taskMAX, CRITERIA_ARG, cli, NULL); + if (s->sock_type == SOCK_STREAM) { shutdown(sock, SHUT_RDWR); close(sock); @@ -119,7 +123,155 @@ end: taskExit(task, NULL); } +static void * +io_txNet(sched_task_t *task) +{ + int wlen; + sock_cli_t *cli = TASK_ARG(task); + sock_t *s = (sock_t*) cli->cli_parent; + if (s->sock_type == SOCK_STREAM) + wlen = send(TASK_FD(task), TASK_DATA(task), TASK_DATLEN(task), 0); + else + wlen = sendto(TASK_FD(task), TASK_DATA(task), TASK_DATLEN(task), 0, + &cli->cli_addr.sa, cli->cli_addr.sa.sa_len); + if (wlen < 1) + schedEvent(TASK_ROOT(task), io_closeClient, cli, 0, NULL, cli->cli_fd); + + taskExit(task, NULL); +} + +static void * +io_txPty(sched_task_t *task) +{ + int wlen; + sock_cli_t *cli = TASK_ARG(task); + + wlen = write(TASK_FD(task), TASK_DATA(task), TASK_DATLEN(task)); + if (wlen < 1) + schedEvent(TASK_ROOT(task), io_closeClient, cli, 0, NULL, cli->cli_fd); + + taskExit(task, NULL); +} + +static void * +io_rxNet(sched_task_t *task) +{ + int rlen; + sock_cli_t *cli = TASK_ARG(task); + sock_t *s = (sock_t*) cli->cli_parent; + sockaddr_t sa; + socklen_t salen = sizeof sa.ss; + + if (s->sock_type == SOCK_STREAM) + rlen = recv(TASK_FD(task), AIT_GET_BUF(&cli->cli_buf[0]), + AIT_LEN(&cli->cli_buf[0]), 0); + else { + rlen = recvfrom(TASK_FD(task), AIT_GET_BUF(&cli->cli_buf[0]), + AIT_LEN(&cli->cli_buf[0]), 0, &sa.sa, &salen); + if (e_addrcmp(&cli->cli_addr, &sa, 42)) + goto end; + } + if (rlen < 1) + schedEvent(TASK_ROOT(task), io_closeClient, cli, 0, NULL, cli->cli_fd); + else + schedWrite(TASK_ROOT(task), io_txPty, cli, cli->cli_pty, + AIT_GET_BUF(&cli->cli_buf[0]), rlen); +end: + schedReadSelf(task); + taskExit(task, NULL); +} + +static void * +io_rxPty(sched_task_t *task) +{ + int rlen; + sock_cli_t *cli = TASK_ARG(task); + + rlen = read(TASK_FD(task), AIT_GET_BUF(&cli->cli_buf[1]), AIT_LEN(&cli->cli_buf[1])); + if (rlen < 1) + schedEvent(TASK_ROOT(task), io_closeClient, cli, 0, NULL, cli->cli_fd); + else + schedWrite(TASK_ROOT(task), io_txNet, cli, cli->cli_fd, + AIT_GET_BUF(&cli->cli_buf[1]), rlen); + + schedReadSelf(task); + taskExit(task, NULL); +} + +static void * +io_bridgeClient(sched_task_t *task) +{ + int c, rlen; + pid_t pid; + sockaddr_t sa; + socklen_t salen = sizeof sa.ss; + sock_cli_t *cli = NULL; + sock_t *s = (sock_t*) TASK_ARG(task); + array_t *args = NULL; + char **argv = NULL; + + if (s->sock_type == SOCK_STREAM) { + if ((c = accept(TASK_FD(task), &sa.sa, &salen)) == -1) { + LOGERR; + goto end; + } + } else { + if ((rlen = recvfrom(TASK_FD(task), + AIT_GET_BUF(&s->sock_buf), AIT_LEN(&s->sock_buf), + MSG_PEEK, &sa.sa, &salen)) == -1) { + LOGERR; + goto end; + } else + c = TASK_FD(task); + } + + cli = e_malloc(sizeof(sock_cli_t)); + if (!cli) { + io_SetErr(elwix_GetErrno(), "%s", elwix_GetError()); + if (s->sock_type == SOCK_STREAM) + close(c); + goto end; + } else { + memset(cli, 0, sizeof(sock_cli_t)); + pthread_mutex_lock(&s->sock_mtx); + TAILQ_INSERT_TAIL(&s->sock_cli, cli, cli_node); + pthread_mutex_unlock(&s->sock_mtx); + } + + cli->cli_parent = TASK_ARG(task); + cli->cli_fd = c; + strlcpy(cli->cli_cmdline, TASK_DATA(task), sizeof cli->cli_cmdline); + memcpy(&cli->cli_addr, &sa, sizeof cli->cli_addr); + AIT_SET_BUFSIZ(&cli->cli_buf[0], 0, AIT_LEN(&s->sock_buf)); + AIT_SET_BUFSIZ(&cli->cli_buf[1], 0, AIT_LEN(&s->sock_buf)); + + switch ((pid = ioForkPTY(&cli->cli_pty, cli->cli_name, sizeof cli->cli_name, + NULL, NULL, NULL))) { + case -1: + ELIBERR(io); + break; + case 0: + array_Args(cli->cli_cmdline, 0, " \t", &args); + argv = array_To(args); + array_Destroy(&args); + + execv(*argv, argv); + break; + default: + schedRead(TASK_ROOT(task), io_rxPty, cli, cli->cli_pty, + TASK_ARG(task), 0); + schedRead(TASK_ROOT(task), io_rxNet, cli, cli->cli_fd, + TASK_ARG(task), 0); + ioUpdTimerSocket(cli); + break; + } +end: + schedReadSelf(task); + taskExit(task, NULL); +} + + /* * ioInitSocket() - Init socket and allocate resources * @@ -224,8 +376,7 @@ ioCloseSocket(sock_t ** __restrict s) schedCancelby((*s)->sock_root, taskTIMER, CRITERIA_DATLEN, (void*) cli->cli_fd, NULL); - schedCancelby((*s)->sock_root, taskMAX, CRITERIA_FD, - (void*) cli->cli_fd, NULL); + schedCancelby((*s)->sock_root, taskMAX, CRITERIA_ARG, cli, NULL); if ((*s)->sock_type == SOCK_STREAM) { shutdown(cli->cli_fd, SHUT_RDWR); @@ -371,6 +522,6 @@ ioBridgeProg2Socket(sock_t * __restrict s, const char if (!s || !prgname || s->sock_kill) return -1; - schedRead(s->sock_root, io_bridgeProg, s, s->sock_fd, prgname, 0); + schedRead(s->sock_root, io_bridgeClient, s, s->sock_fd, (void*) prgname, 0); return schedRun(s->sock_root, &s->sock_kill); }