Annotation of libaitio/src/sock.c, revision 1.5.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.5.2.1 ! misho 6: * $Id: sock.c,v 1.5 2013/11/22 13:49:14 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;
54: int stat, sock = (int) TASK_DATLEN(task);
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) {
63: shutdown(sock, SHUT_RDWR);
64: close(sock);
65: }
66: AIT_FREE_VAL(&cli->cli_buf[1]);
67: AIT_FREE_VAL(&cli->cli_buf[0]);
68:
69: if (cli->cli_pid > 0) {
70: kill(cli->cli_pid, SIGTERM);
71: while (waitpid(cli->cli_pid, &stat, WNOHANG) > 0) {
72: usleep(1000);
73: kill(cli->cli_pid, SIGTERM);
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);
126: ioUpdTimerSocket(cli, NULL);
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:
139: ioUpdTimerSocket(cli, NULL);
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)
147: schedEvent(TASK_ROOT(task), io_closeClient, cli, 0,
148: (void*) cli->cli_func, cli->cli_fd);
149:
150: taskExit(task, NULL);
151: }
152:
153: static void *
154: io_txPty(sched_task_t *task)
155: {
156: int wlen;
157: sock_cli_t *cli = TASK_ARG(task);
158:
159: ioUpdTimerSocket(cli, NULL);
160:
161: wlen = write(TASK_FD(task), TASK_DATA(task), TASK_DATLEN(task));
162: if (wlen < 1)
163: schedEvent(TASK_ROOT(task), io_closeClient, cli, 0,
164: (void*) cli->cli_func, cli->cli_fd);
165:
166: taskExit(task, NULL);
167: }
168:
169: static void *
170: io_rxNet(sched_task_t *task)
171: {
172: int rlen;
173: sock_cli_t *cli = TASK_ARG(task);
174: sock_t *s = (sock_t*) cli->cli_parent;
175: sockaddr_t sa;
176: socklen_t salen = sizeof sa.ss;
177:
178: ioUpdTimerSocket(cli, NULL);
179:
180: if (s->sock_type == SOCK_STREAM)
181: rlen = recv(TASK_FD(task), AIT_GET_BUF(&cli->cli_buf[0]),
182: AIT_LEN(&cli->cli_buf[0]), 0);
183: else {
184: rlen = recvfrom(TASK_FD(task), AIT_GET_BUF(&cli->cli_buf[0]),
185: AIT_LEN(&cli->cli_buf[0]), 0, &sa.sa, &salen);
186: if (e_addrcmp(&cli->cli_addr, &sa, 42))
187: goto end;
188: }
189: if (rlen < 1)
190: schedEvent(TASK_ROOT(task), io_closeClient, cli, 0,
191: (void*) cli->cli_func, cli->cli_fd);
192: else
193: schedEvent(TASK_ROOT(task), io_txPty, cli, cli->cli_pty,
194: AIT_GET_BUF(&cli->cli_buf[0]), rlen);
195: end:
196: schedReadSelf(task);
197: taskExit(task, NULL);
198: }
199:
200: static void *
201: io_rxPty(sched_task_t *task)
202: {
203: int rlen;
204: sock_cli_t *cli = TASK_ARG(task);
205:
206: ioUpdTimerSocket(cli, NULL);
207:
208: rlen = read(TASK_FD(task), AIT_GET_BUF(&cli->cli_buf[1]), AIT_LEN(&cli->cli_buf[1]));
209: if (rlen < 1)
210: schedEvent(TASK_ROOT(task), io_closeClient, cli, 0,
211: (void*) cli->cli_func, cli->cli_fd);
212: else
213: schedEvent(TASK_ROOT(task), io_txNet, cli, cli->cli_fd,
214: AIT_GET_BUF(&cli->cli_buf[1]), rlen);
215:
216: schedReadSelf(task);
217: taskExit(task, NULL);
218: }
219:
220: static void *
221: io_bridgeClient(sched_task_t *task)
222: {
223: int c, rlen;
224: pid_t pid;
225: sockaddr_t sa;
226: socklen_t salen = sizeof sa.ss;
227: sock_cli_t *cli = NULL;
228: sock_t *s = (sock_t*) TASK_ARG(task);
229: array_t *args = NULL;
230: char **argv = NULL;
231:
232: if (s->sock_type == SOCK_STREAM) {
233: if ((c = accept(TASK_FD(task), &sa.sa, &salen)) == -1) {
234: LOGERR;
235: goto end;
236: }
237: } else {
238: if ((rlen = recvfrom(TASK_FD(task),
239: AIT_GET_BUF(&s->sock_buf), AIT_LEN(&s->sock_buf),
240: MSG_PEEK, &sa.sa, &salen)) == -1) {
241: LOGERR;
242: goto end;
243: } else
244: c = TASK_FD(task);
245: }
246:
247: cli = e_malloc(sizeof(sock_cli_t));
248: if (!cli) {
249: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
250: if (s->sock_type == SOCK_STREAM)
251: close(c);
252: goto end;
253: } else {
254: memset(cli, 0, sizeof(sock_cli_t));
255: pthread_mutex_lock(&s->sock_mtx);
256: TAILQ_INSERT_TAIL(&s->sock_cli, cli, cli_node);
257: pthread_mutex_unlock(&s->sock_mtx);
258: }
259:
260: cli->cli_parent = TASK_ARG(task);
261: cli->cli_fd = c;
262: strlcpy(cli->cli_cmdline, TASK_DATA(task), sizeof cli->cli_cmdline);
263: memcpy(&cli->cli_addr, &sa, sizeof cli->cli_addr);
264: AIT_SET_BUFSIZ(&cli->cli_buf[0], 0, AIT_LEN(&s->sock_buf));
265: AIT_SET_BUFSIZ(&cli->cli_buf[1], 0, AIT_LEN(&s->sock_buf));
266:
267: switch ((pid = ioForkPTY(&cli->cli_pty, cli->cli_name, sizeof cli->cli_name,
268: NULL, NULL, NULL))) {
269: case -1:
270: ELIBERR(io);
271: break;
272: case 0:
273: array_Args(cli->cli_cmdline, 0, " \t", &args);
274: argv = array_To(args);
275: array_Destroy(&args);
276:
277: printf("Console %s\n", cli->cli_name);
1.5.2.1 ! misho 278: rlen = execv(*argv, argv);
! 279: _exit(rlen);
1.5 misho 280: break;
281: default:
282: cli->cli_pid = pid;
283:
284: schedRead(TASK_ROOT(task), io_rxPty, cli, cli->cli_pty,
285: TASK_ARG(task), 0);
286: schedRead(TASK_ROOT(task), io_rxNet, cli, cli->cli_fd,
287: TASK_ARG(task), 0);
288: ioUpdTimerSocket(cli, NULL);
289: break;
290: }
291: end:
292: schedReadSelf(task);
293: taskExit(task, NULL);
294: }
295:
296:
1.2 misho 297: /*
298: * ioInitSocket() - Init socket and allocate resources
299: *
300: * @role = Socket role
301: * @type = Socket type
302: * @proto = Socket protocol
303: * @addr = Bind to address
304: * @port = Bind to port
305: * @buflen = Socket buffer, optional if =0 == BUFSIZ
306: * return: NULL error or !=NULL created socket
307: */
308: sock_t *
309: ioInitSocket(int role, int type, int proto, const char *addr, u_short port, size_t buflen)
310: {
311: sock_t *s = NULL;
312: int n = 1;
313:
314: if (!addr)
315: return NULL;
316:
317: s = e_malloc(sizeof(sock_t));
318: if (!s) {
319: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
320: return NULL;
321: } else
322: memset(s, 0, sizeof(sock_t));
323:
1.3 misho 324: TAILQ_INIT(&s->sock_cli);
325:
1.2 misho 326: s->sock_role = role;
327: s->sock_type = type;
328: s->sock_proto = proto;
329: if (!e_gethostbyname(addr, port, &s->sock_addr)) {
330: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
331: e_free(s);
332: return NULL;
333: } else {
334: buflen = buflen ? buflen : BUFSIZ;
1.5 misho 335: buflen = E_ALIGN(buflen, 2); /* align buflen length */
1.2 misho 336: AIT_SET_BUFSIZ(&s->sock_buf, 0, buflen);
337: }
338:
339: s->sock_fd = socket(s->sock_addr.sa.sa_family, s->sock_type, s->sock_proto);
340: if (s->sock_fd == -1) {
341: LOGERR;
342: AIT_FREE_VAL(&s->sock_buf);
343: e_free(s);
344: return NULL;
345: }
346: if (setsockopt(s->sock_fd, SOL_SOCKET, SO_SNDBUF, &buflen, sizeof buflen) == -1) {
347: LOGERR;
348: AIT_FREE_VAL(&s->sock_buf);
349: e_free(s);
350: return NULL;
351: }
352: if (setsockopt(s->sock_fd, SOL_SOCKET, SO_RCVBUF, &buflen, sizeof buflen) == -1) {
353: LOGERR;
354: AIT_FREE_VAL(&s->sock_buf);
355: e_free(s);
356: return NULL;
357: }
358: if (setsockopt(s->sock_fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) == -1) {
359: LOGERR;
360: AIT_FREE_VAL(&s->sock_buf);
361: e_free(s);
362: return NULL;
363: }
364: if (bind(s->sock_fd, &s->sock_addr.sa, s->sock_addr.sa.sa_len) == -1) {
365: LOGERR;
366: AIT_FREE_VAL(&s->sock_buf);
367: e_free(s);
368: return NULL;
369: }
370:
1.5 misho 371: s->sock_root = schedBegin();
372: if (!s->sock_root) {
373: io_SetErr(sched_GetErrno(), "%s", sched_GetError());
374: AIT_FREE_VAL(&s->sock_buf);
375: e_free(s);
376: return NULL;
377: }
378:
1.3 misho 379: pthread_mutex_init(&s->sock_mtx, NULL);
1.2 misho 380: return s;
381: }
382:
383: /*
384: * ioCloseSocket() - Close socket and free resources
385: *
386: * @s = Socket
387: * return: none
388: */
389: void
390: ioCloseSocket(sock_t ** __restrict s)
391: {
1.5 misho 392: sock_cli_t *cli;
393: int stat;
1.3 misho 394:
1.2 misho 395: if (s && *s) {
1.3 misho 396: pthread_mutex_lock(&(*s)->sock_mtx);
397: while ((cli = TAILQ_FIRST(&(*s)->sock_cli))) {
398: TAILQ_REMOVE(&(*s)->sock_cli, cli, cli_node);
1.5 misho 399:
400: schedCancelby((*s)->sock_root, taskMAX, CRITERIA_ARG, cli, NULL);
401:
402: if ((*s)->sock_type == SOCK_STREAM) {
403: shutdown(cli->cli_fd, SHUT_RDWR);
404: close(cli->cli_fd);
405: }
406: AIT_FREE_VAL(&cli->cli_buf[1]);
407: AIT_FREE_VAL(&cli->cli_buf[0]);
408:
409: if (cli->cli_pid > 0) {
410: kill(cli->cli_pid, SIGTERM);
411: while (waitpid(cli->cli_pid, &stat, WNOHANG) > 0) {
412: usleep(1000);
413: kill(cli->cli_pid, SIGTERM);
414: }
415: }
416:
1.3 misho 417: e_free(cli);
418: }
419: pthread_mutex_unlock(&(*s)->sock_mtx);
420:
1.2 misho 421: shutdown((*s)->sock_fd, SHUT_RDWR);
422: close((*s)->sock_fd);
423:
424: AIT_FREE_VAL(&(*s)->sock_buf);
1.3 misho 425:
1.5 misho 426: schedEnd(&(*s)->sock_root);
427:
1.3 misho 428: pthread_mutex_destroy(&(*s)->sock_mtx);
1.2 misho 429: e_free(*s);
430: *s = NULL;
431: }
432: }
433:
434: /*
435: * ioUpSocket() - Setup socket for use
436: *
437: * @s = Socket
438: * @arg = Server role = listen backlog queue and Client role = peer address
1.5 misho 439: * @timeout = Socket timeout in sec (default -1 infinit)
1.2 misho 440: * return: -1 error or 0 ok
441: */
442: int
1.5 misho 443: ioUpSocket(sock_t * __restrict s, void *arg, int timeout)
1.2 misho 444: {
445: int ret = 0;
446: sockaddr_t *peer = (sockaddr_t*) arg;
447: uintptr_t backlog = (uintptr_t) arg;
448:
449: if (!s || !arg)
450: return -1;
1.5 misho 451: else {
452: s->sock_timeout.tv_sec = timeout;
453: s->sock_timeout.tv_nsec = (timeout < 1) ? timeout : 0;
454: schedPolling(s->sock_root, &s->sock_timeout, NULL);
455: }
1.2 misho 456:
457: switch (s->sock_role) {
458: case IO_SOCK_ROLE_CLIENT:
459: memcpy(&s->sock_peer, peer, sizeof s->sock_peer);
460:
461: if (connect(s->sock_fd, &s->sock_peer.sa,
462: s->sock_peer.sa.sa_len) == -1) {
463: LOGERR;
464: return -1;
465: }
466: break;
467: case IO_SOCK_ROLE_SERVER:
468: if (s->sock_type == SOCK_STREAM) {
469: s->sock_backq = backlog;
470:
471: if (listen(s->sock_fd, s->sock_backq) == -1) {
472: LOGERR;
473: return -1;
474: }
475: }
476: break;
477: default:
478: io_SetErr(EINVAL, "Unsupported socket type");
479: return -1;
480: }
481:
482: fcntl(s->sock_fd, F_SETFL, fcntl(s->sock_fd, F_GETFL) | O_NONBLOCK);
483: return ret;
484: }
1.3 misho 485:
1.5 misho 486: /*
487: * ioUpdTimerSocket() - Update timeout of socket
488: *
489: * @c = Client socket
490: * @arg = Optional data argument
491: * return: none
492: */
493: void
494: ioUpdTimerSocket(sock_cli_t * __restrict c, void *arg)
1.3 misho 495: {
1.5 misho 496: sock_t *s;
1.3 misho 497:
1.5 misho 498: if (!c)
499: return;
500: else
501: s = c->cli_parent;
1.3 misho 502:
1.5 misho 503: schedCancelby(s->sock_root, taskTIMER, CRITERIA_DATLEN, (void*) c->cli_fd, NULL);
504: schedTimer(s->sock_root, io_closeClient, c, s->sock_timeout, arg, c->cli_fd);
1.3 misho 505: }
506:
1.5 misho 507: /*
508: * ioCloseClient() - Close client socket
509: *
510: * @c = Client socket
511: * return: 0 ok or !=0 error
512: */
513: int
514: ioCloseClient(sock_cli_t * __restrict c)
1.3 misho 515: {
1.5 misho 516: sock_t *s;
1.3 misho 517:
1.5 misho 518: if (!c)
519: return -1;
520: else
521: s = c->cli_parent;
1.3 misho 522:
1.5 misho 523: return !schedEvent(s->sock_root, io_closeClient, c, 0, NULL, c->cli_fd);
1.3 misho 524: }
525:
526: /*
1.5 misho 527: * ioLoopSocket() - Start socket scheduler
1.3 misho 528: *
529: * @s = Socket
1.5 misho 530: * @rcb = Read callback
531: * return: -1 error or return result from scheduler
1.3 misho 532: */
533: int
1.5 misho 534: ioLoopSocket(sock_t * __restrict s, sched_task_func_t rcb)
1.3 misho 535: {
1.5 misho 536: if (!s || !rcb || s->sock_kill)
1.3 misho 537: return -1;
538:
1.5 misho 539: schedRead(s->sock_root, io_acceptClient, s, s->sock_fd, rcb, 0);
540: return schedRun(s->sock_root, &s->sock_kill);
541: }
1.3 misho 542:
1.5 misho 543: /*
544: * ioBridgeProg2Socket() - Start socket scheduler and bridge program to socket
545: *
546: * @s = Socket
547: * @prgname = Program name
548: * return: 0 ok or !=0 error
549: */
550: int
551: ioBridgeProg2Socket(sock_t * __restrict s, const char *prgname)
552: {
553: if (!s || !prgname || s->sock_kill)
554: return -1;
1.3 misho 555:
1.5 misho 556: schedRead(s->sock_root, io_bridgeClient, s, s->sock_fd, (void*) prgname, 0);
557: return schedRun(s->sock_root, &s->sock_kill);
1.3 misho 558: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>