Annotation of libaitio/src/sock.c, revision 1.6.2.1
1.2 misho 1: /*************************************************************************
2: * (C) 2013 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
1.6.2.1 ! misho 6: * $Id: sock.c,v 1.6 2013/11/22 14:31:08 misho Exp $
1.2 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
1.5 misho 49: static void *
50: io_closeClient(sched_task_t *task)
51: {
52: sock_cli_t *cli = (sock_cli_t*) TASK_ARG(task);
53: sock_t *s = (sock_t*) cli->cli_parent;
1.6.2.1 ! misho 54: int stat;
1.5 misho 55:
56: pthread_mutex_lock(&s->sock_mtx);
57: TAILQ_REMOVE(&s->sock_cli, cli, cli_node);
58: pthread_mutex_unlock(&s->sock_mtx);
59:
60: schedCancelby(s->sock_root, taskMAX, CRITERIA_ARG, cli, NULL);
61:
62: if (s->sock_type == SOCK_STREAM) {
1.6.2.1 ! misho 63: shutdown(cli->cli_fd, SHUT_RDWR);
! 64: close(cli->cli_fd);
1.5 misho 65: }
66: AIT_FREE_VAL(&cli->cli_buf[1]);
67: AIT_FREE_VAL(&cli->cli_buf[0]);
68:
69: if (cli->cli_pid > 0) {
1.6.2.1 ! misho 70: kill(cli->cli_pid, SIGKILL);
1.5 misho 71: while (waitpid(cli->cli_pid, &stat, WNOHANG) > 0) {
72: usleep(1000);
1.6.2.1 ! misho 73: kill(cli->cli_pid, SIGKILL);
1.5 misho 74: }
75: }
76:
77: e_free(cli);
78: taskExit(task, NULL);
79: }
80:
81: static void *
82: io_acceptClient(sched_task_t *task)
83: {
84: int c, rlen;
85: sockaddr_t sa;
86: socklen_t salen = sizeof sa.ss;
87: sock_cli_t *cli = NULL;
88: sock_t *s = (sock_t*) TASK_ARG(task);
89:
90: if (s->sock_type == SOCK_STREAM) {
91: if ((c = accept(TASK_FD(task), &sa.sa, &salen)) == -1) {
92: LOGERR;
93: goto end;
94: }
95: } else {
96: if ((rlen = recvfrom(TASK_FD(task),
97: AIT_GET_BUF(&s->sock_buf), AIT_LEN(&s->sock_buf),
98: MSG_PEEK, &sa.sa, &salen)) == -1) {
99: LOGERR;
100: goto end;
101: } else
102: c = TASK_FD(task);
103: }
104:
105: cli = e_malloc(sizeof(sock_cli_t));
106: if (!cli) {
107: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
108: if (s->sock_type == SOCK_STREAM)
109: close(c);
110: goto end;
111: } else {
112: memset(cli, 0, sizeof(sock_cli_t));
113: pthread_mutex_lock(&s->sock_mtx);
114: TAILQ_INSERT_TAIL(&s->sock_cli, cli, cli_node);
115: pthread_mutex_unlock(&s->sock_mtx);
116: }
117:
118: cli->cli_parent = TASK_ARG(task);
119: cli->cli_fd = c;
120: cli->cli_func = TASK_DATA(task);
121: memcpy(&cli->cli_addr, &sa, sizeof cli->cli_addr);
122: AIT_SET_BUFSIZ(&cli->cli_buf[0], 0, AIT_LEN(&s->sock_buf));
123: AIT_SET_BUFSIZ(&cli->cli_buf[1], 0, AIT_LEN(&s->sock_buf));
124:
125: schedRead(TASK_ROOT(task), cli->cli_func, cli, cli->cli_fd, TASK_ARG(task), 0);
1.6.2.1 ! misho 126: ioUpdTimerSocket(cli);
1.5 misho 127: end:
128: schedReadSelf(task);
129: taskExit(task, NULL);
130: }
131:
132: static void *
133: io_txNet(sched_task_t *task)
134: {
135: int wlen;
136: sock_cli_t *cli = TASK_ARG(task);
137: sock_t *s = (sock_t*) cli->cli_parent;
138:
1.6.2.1 ! misho 139: ioUpdTimerSocket(cli);
1.5 misho 140:
141: if (s->sock_type == SOCK_STREAM)
142: wlen = send(TASK_FD(task), TASK_DATA(task), TASK_DATLEN(task), 0);
143: else
144: wlen = sendto(TASK_FD(task), TASK_DATA(task), TASK_DATLEN(task), 0,
145: &cli->cli_addr.sa, cli->cli_addr.sa.sa_len);
146: if (wlen < 1)
1.6.2.1 ! misho 147: schedEvent(TASK_ROOT(task), io_closeClient, cli, 0, NULL, 0);
1.5 misho 148:
149: taskExit(task, NULL);
150: }
151:
152: static void *
153: io_txPty(sched_task_t *task)
154: {
155: int wlen;
156: sock_cli_t *cli = TASK_ARG(task);
157:
1.6.2.1 ! misho 158: ioUpdTimerSocket(cli);
1.5 misho 159:
160: wlen = write(TASK_FD(task), TASK_DATA(task), TASK_DATLEN(task));
161: if (wlen < 1)
1.6.2.1 ! misho 162: schedEvent(TASK_ROOT(task), io_closeClient, cli, 0, NULL, 0);
1.5 misho 163:
164: taskExit(task, NULL);
165: }
166:
167: static void *
168: io_rxNet(sched_task_t *task)
169: {
170: int rlen;
171: sock_cli_t *cli = TASK_ARG(task);
172: sock_t *s = (sock_t*) cli->cli_parent;
173: sockaddr_t sa;
174: socklen_t salen = sizeof sa.ss;
175:
1.6.2.1 ! misho 176: ioUpdTimerSocket(cli);
1.5 misho 177:
178: if (s->sock_type == SOCK_STREAM)
179: rlen = recv(TASK_FD(task), AIT_GET_BUF(&cli->cli_buf[0]),
180: AIT_LEN(&cli->cli_buf[0]), 0);
181: else {
182: rlen = recvfrom(TASK_FD(task), AIT_GET_BUF(&cli->cli_buf[0]),
183: AIT_LEN(&cli->cli_buf[0]), 0, &sa.sa, &salen);
184: if (e_addrcmp(&cli->cli_addr, &sa, 42))
185: goto end;
186: }
187: if (rlen < 1)
1.6.2.1 ! misho 188: schedEvent(TASK_ROOT(task), io_closeClient, cli, 0, NULL, 0);
1.5 misho 189: else
190: schedEvent(TASK_ROOT(task), io_txPty, cli, cli->cli_pty,
191: AIT_GET_BUF(&cli->cli_buf[0]), rlen);
192: end:
193: schedReadSelf(task);
194: taskExit(task, NULL);
195: }
196:
197: static void *
198: io_rxPty(sched_task_t *task)
199: {
200: int rlen;
201: sock_cli_t *cli = TASK_ARG(task);
202:
1.6.2.1 ! misho 203: ioUpdTimerSocket(cli);
1.5 misho 204:
205: rlen = read(TASK_FD(task), AIT_GET_BUF(&cli->cli_buf[1]), AIT_LEN(&cli->cli_buf[1]));
206: if (rlen < 1)
1.6.2.1 ! misho 207: schedEvent(TASK_ROOT(task), io_closeClient, cli, 0, NULL, 0);
1.5 misho 208: else
209: schedEvent(TASK_ROOT(task), io_txNet, cli, cli->cli_fd,
210: AIT_GET_BUF(&cli->cli_buf[1]), rlen);
211:
212: schedReadSelf(task);
213: taskExit(task, NULL);
214: }
215:
216: static void *
217: io_bridgeClient(sched_task_t *task)
218: {
219: int c, rlen;
220: pid_t pid;
221: sockaddr_t sa;
222: socklen_t salen = sizeof sa.ss;
223: sock_cli_t *cli = NULL;
224: sock_t *s = (sock_t*) TASK_ARG(task);
225: array_t *args = NULL;
226: char **argv = NULL;
227:
228: if (s->sock_type == SOCK_STREAM) {
229: if ((c = accept(TASK_FD(task), &sa.sa, &salen)) == -1) {
230: LOGERR;
231: goto end;
232: }
233: } else {
234: if ((rlen = recvfrom(TASK_FD(task),
235: AIT_GET_BUF(&s->sock_buf), AIT_LEN(&s->sock_buf),
236: MSG_PEEK, &sa.sa, &salen)) == -1) {
237: LOGERR;
238: goto end;
239: } else
240: c = TASK_FD(task);
241: }
242:
243: cli = e_malloc(sizeof(sock_cli_t));
244: if (!cli) {
245: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
246: if (s->sock_type == SOCK_STREAM)
247: close(c);
248: goto end;
249: } else {
250: memset(cli, 0, sizeof(sock_cli_t));
251: pthread_mutex_lock(&s->sock_mtx);
252: TAILQ_INSERT_TAIL(&s->sock_cli, cli, cli_node);
253: pthread_mutex_unlock(&s->sock_mtx);
254: }
255:
256: cli->cli_parent = TASK_ARG(task);
257: cli->cli_fd = c;
258: strlcpy(cli->cli_cmdline, TASK_DATA(task), sizeof cli->cli_cmdline);
259: memcpy(&cli->cli_addr, &sa, sizeof cli->cli_addr);
260: AIT_SET_BUFSIZ(&cli->cli_buf[0], 0, AIT_LEN(&s->sock_buf));
261: AIT_SET_BUFSIZ(&cli->cli_buf[1], 0, AIT_LEN(&s->sock_buf));
262:
263: switch ((pid = ioForkPTY(&cli->cli_pty, cli->cli_name, sizeof cli->cli_name,
264: NULL, NULL, NULL))) {
265: case -1:
266: ELIBERR(io);
267: break;
268: case 0:
269: array_Args(cli->cli_cmdline, 0, " \t", &args);
270: argv = array_To(args);
271: array_Destroy(&args);
272:
273: printf("Console %s\n", cli->cli_name);
1.6 misho 274: rlen = execv(*argv, argv);
275: _exit(rlen);
1.5 misho 276: break;
277: default:
278: cli->cli_pid = pid;
279:
280: schedRead(TASK_ROOT(task), io_rxPty, cli, cli->cli_pty,
281: TASK_ARG(task), 0);
282: schedRead(TASK_ROOT(task), io_rxNet, cli, cli->cli_fd,
283: TASK_ARG(task), 0);
1.6.2.1 ! misho 284: ioUpdTimerSocket(cli);
1.5 misho 285: break;
286: }
287: end:
288: schedReadSelf(task);
289: taskExit(task, NULL);
290: }
291:
292:
1.2 misho 293: /*
294: * ioInitSocket() - Init socket and allocate resources
295: *
296: * @role = Socket role
297: * @type = Socket type
298: * @proto = Socket protocol
299: * @addr = Bind to address
300: * @port = Bind to port
301: * @buflen = Socket buffer, optional if =0 == BUFSIZ
302: * return: NULL error or !=NULL created socket
303: */
304: sock_t *
305: ioInitSocket(int role, int type, int proto, const char *addr, u_short port, size_t buflen)
306: {
307: sock_t *s = NULL;
308: int n = 1;
309:
310: if (!addr)
311: return NULL;
312:
313: s = e_malloc(sizeof(sock_t));
314: if (!s) {
315: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
316: return NULL;
317: } else
318: memset(s, 0, sizeof(sock_t));
319:
1.3 misho 320: TAILQ_INIT(&s->sock_cli);
321:
1.2 misho 322: s->sock_role = role;
323: s->sock_type = type;
324: s->sock_proto = proto;
325: if (!e_gethostbyname(addr, port, &s->sock_addr)) {
326: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
327: e_free(s);
328: return NULL;
329: } else {
330: buflen = buflen ? buflen : BUFSIZ;
1.5 misho 331: buflen = E_ALIGN(buflen, 2); /* align buflen length */
1.2 misho 332: AIT_SET_BUFSIZ(&s->sock_buf, 0, buflen);
333: }
334:
335: s->sock_fd = socket(s->sock_addr.sa.sa_family, s->sock_type, s->sock_proto);
336: if (s->sock_fd == -1) {
337: LOGERR;
338: AIT_FREE_VAL(&s->sock_buf);
339: e_free(s);
340: return NULL;
341: }
342: if (setsockopt(s->sock_fd, SOL_SOCKET, SO_SNDBUF, &buflen, sizeof buflen) == -1) {
343: LOGERR;
344: AIT_FREE_VAL(&s->sock_buf);
345: e_free(s);
346: return NULL;
347: }
348: if (setsockopt(s->sock_fd, SOL_SOCKET, SO_RCVBUF, &buflen, sizeof buflen) == -1) {
349: LOGERR;
350: AIT_FREE_VAL(&s->sock_buf);
351: e_free(s);
352: return NULL;
353: }
354: if (setsockopt(s->sock_fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) == -1) {
355: LOGERR;
356: AIT_FREE_VAL(&s->sock_buf);
357: e_free(s);
358: return NULL;
359: }
360: if (bind(s->sock_fd, &s->sock_addr.sa, s->sock_addr.sa.sa_len) == -1) {
361: LOGERR;
362: AIT_FREE_VAL(&s->sock_buf);
363: e_free(s);
364: return NULL;
365: }
366:
1.5 misho 367: s->sock_root = schedBegin();
368: if (!s->sock_root) {
369: io_SetErr(sched_GetErrno(), "%s", sched_GetError());
370: AIT_FREE_VAL(&s->sock_buf);
371: e_free(s);
372: return NULL;
373: }
374:
1.3 misho 375: pthread_mutex_init(&s->sock_mtx, NULL);
1.2 misho 376: return s;
377: }
378:
379: /*
380: * ioCloseSocket() - Close socket and free resources
381: *
382: * @s = Socket
383: * return: none
384: */
385: void
386: ioCloseSocket(sock_t ** __restrict s)
387: {
1.5 misho 388: sock_cli_t *cli;
389: int stat;
1.3 misho 390:
1.2 misho 391: if (s && *s) {
1.3 misho 392: pthread_mutex_lock(&(*s)->sock_mtx);
393: while ((cli = TAILQ_FIRST(&(*s)->sock_cli))) {
394: TAILQ_REMOVE(&(*s)->sock_cli, cli, cli_node);
1.5 misho 395:
396: schedCancelby((*s)->sock_root, taskMAX, CRITERIA_ARG, cli, NULL);
397:
398: if ((*s)->sock_type == SOCK_STREAM) {
399: shutdown(cli->cli_fd, SHUT_RDWR);
400: close(cli->cli_fd);
401: }
402: AIT_FREE_VAL(&cli->cli_buf[1]);
403: AIT_FREE_VAL(&cli->cli_buf[0]);
404:
405: if (cli->cli_pid > 0) {
1.6.2.1 ! misho 406: kill(cli->cli_pid, SIGKILL);
1.5 misho 407: while (waitpid(cli->cli_pid, &stat, WNOHANG) > 0) {
408: usleep(1000);
1.6.2.1 ! misho 409: kill(cli->cli_pid, SIGKILL);
1.5 misho 410: }
411: }
412:
1.3 misho 413: e_free(cli);
414: }
415: pthread_mutex_unlock(&(*s)->sock_mtx);
416:
1.2 misho 417: shutdown((*s)->sock_fd, SHUT_RDWR);
418: close((*s)->sock_fd);
419:
420: AIT_FREE_VAL(&(*s)->sock_buf);
1.3 misho 421:
1.5 misho 422: schedEnd(&(*s)->sock_root);
423:
1.3 misho 424: pthread_mutex_destroy(&(*s)->sock_mtx);
1.2 misho 425: e_free(*s);
426: *s = NULL;
427: }
428: }
429:
430: /*
431: * ioUpSocket() - Setup socket for use
432: *
433: * @s = Socket
434: * @arg = Server role = listen backlog queue and Client role = peer address
1.5 misho 435: * @timeout = Socket timeout in sec (default -1 infinit)
1.2 misho 436: * return: -1 error or 0 ok
437: */
438: int
1.5 misho 439: ioUpSocket(sock_t * __restrict s, void *arg, int timeout)
1.2 misho 440: {
441: int ret = 0;
442: sockaddr_t *peer = (sockaddr_t*) arg;
443: uintptr_t backlog = (uintptr_t) arg;
444:
445: if (!s || !arg)
446: return -1;
1.5 misho 447: else {
448: s->sock_timeout.tv_sec = timeout;
449: s->sock_timeout.tv_nsec = (timeout < 1) ? timeout : 0;
450: schedPolling(s->sock_root, &s->sock_timeout, NULL);
451: }
1.2 misho 452:
453: switch (s->sock_role) {
454: case IO_SOCK_ROLE_CLIENT:
455: memcpy(&s->sock_peer, peer, sizeof s->sock_peer);
456:
457: if (connect(s->sock_fd, &s->sock_peer.sa,
458: s->sock_peer.sa.sa_len) == -1) {
459: LOGERR;
460: return -1;
461: }
462: break;
463: case IO_SOCK_ROLE_SERVER:
464: if (s->sock_type == SOCK_STREAM) {
465: s->sock_backq = backlog;
466:
467: if (listen(s->sock_fd, s->sock_backq) == -1) {
468: LOGERR;
469: return -1;
470: }
471: }
472: break;
473: default:
474: io_SetErr(EINVAL, "Unsupported socket type");
475: return -1;
476: }
477:
478: fcntl(s->sock_fd, F_SETFL, fcntl(s->sock_fd, F_GETFL) | O_NONBLOCK);
479: return ret;
480: }
1.3 misho 481:
1.5 misho 482: /*
483: * ioUpdTimerSocket() - Update timeout of socket
484: *
485: * @c = Client socket
486: * return: none
487: */
488: void
1.6.2.1 ! misho 489: ioUpdTimerSocket(sock_cli_t * __restrict c)
1.3 misho 490: {
1.5 misho 491: sock_t *s;
1.3 misho 492:
1.5 misho 493: if (!c)
494: return;
495: else
496: s = c->cli_parent;
1.3 misho 497:
1.6.2.1 ! misho 498: schedCancelby(s->sock_root, taskTIMER, CRITERIA_ARG, c, NULL);
! 499: schedTimer(s->sock_root, io_closeClient, c, s->sock_timeout, NULL, 0);
1.3 misho 500: }
501:
1.5 misho 502: /*
503: * ioCloseClient() - Close client socket
504: *
505: * @c = Client socket
506: * return: 0 ok or !=0 error
507: */
508: int
509: ioCloseClient(sock_cli_t * __restrict c)
1.3 misho 510: {
1.5 misho 511: sock_t *s;
1.3 misho 512:
1.5 misho 513: if (!c)
514: return -1;
515: else
516: s = c->cli_parent;
1.3 misho 517:
1.6.2.1 ! misho 518: return !schedEvent(s->sock_root, io_closeClient, c, 0, NULL, 0);
1.3 misho 519: }
520:
521: /*
1.5 misho 522: * ioLoopSocket() - Start socket scheduler
1.3 misho 523: *
524: * @s = Socket
1.5 misho 525: * @rcb = Read callback
526: * return: -1 error or return result from scheduler
1.3 misho 527: */
528: int
1.5 misho 529: ioLoopSocket(sock_t * __restrict s, sched_task_func_t rcb)
1.3 misho 530: {
1.5 misho 531: if (!s || !rcb || s->sock_kill)
1.3 misho 532: return -1;
533:
1.5 misho 534: schedRead(s->sock_root, io_acceptClient, s, s->sock_fd, rcb, 0);
535: return schedRun(s->sock_root, &s->sock_kill);
536: }
1.3 misho 537:
1.5 misho 538: /*
539: * ioBridgeProg2Socket() - Start socket scheduler and bridge program to socket
540: *
541: * @s = Socket
542: * @prgname = Program name
543: * return: 0 ok or !=0 error
544: */
545: int
546: ioBridgeProg2Socket(sock_t * __restrict s, const char *prgname)
547: {
548: if (!s || !prgname || s->sock_kill)
549: return -1;
1.3 misho 550:
1.5 misho 551: schedRead(s->sock_root, io_bridgeClient, s, s->sock_fd, (void*) prgname, 0);
552: return schedRun(s->sock_root, &s->sock_kill);
1.3 misho 553: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>