Annotation of libaitio/src/sock.c, revision 1.4.4.8
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.4.4.8 ! misho 6: * $Id: sock.c,v 1.4.4.7 2013/11/22 08:23:51 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.4.4.4 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 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:
1.4.4.7 misho 60: schedCancelby(s->sock_root, taskTIMER, CRITERIA_DATLEN,
61: (void*) cli->cli_fd, NULL);
62: schedCancelby(s->sock_root, taskMAX, CRITERIA_ARG, cli, NULL);
63:
1.4.4.4 misho 64: if (s->sock_type == SOCK_STREAM) {
65: shutdown(sock, SHUT_RDWR);
66: close(sock);
67: }
1.4.4.5 misho 68: AIT_FREE_VAL(&cli->cli_buf[1]);
69: AIT_FREE_VAL(&cli->cli_buf[0]);
1.4.4.4 misho 70:
71: e_free(cli);
72: taskExit(task, NULL);
73: }
74:
75: static void *
76: io_acceptClient(sched_task_t *task)
77: {
78: int c, rlen;
79: sockaddr_t sa;
80: socklen_t salen = sizeof sa.ss;
81: sock_cli_t *cli = NULL;
82: sock_t *s = (sock_t*) TASK_ARG(task);
83:
84: if (s->sock_type == SOCK_STREAM) {
85: if ((c = accept(TASK_FD(task), &sa.sa, &salen)) == -1) {
86: LOGERR;
87: goto end;
88: }
89: } else {
90: if ((rlen = recvfrom(TASK_FD(task),
91: AIT_GET_BUF(&s->sock_buf), AIT_LEN(&s->sock_buf),
92: MSG_PEEK, &sa.sa, &salen)) == -1) {
93: LOGERR;
94: goto end;
95: } else
96: c = TASK_FD(task);
97: }
98:
99: cli = e_malloc(sizeof(sock_cli_t));
100: if (!cli) {
101: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
102: if (s->sock_type == SOCK_STREAM)
103: close(c);
104: goto end;
105: } else {
106: memset(cli, 0, sizeof(sock_cli_t));
107: pthread_mutex_lock(&s->sock_mtx);
108: TAILQ_INSERT_TAIL(&s->sock_cli, cli, cli_node);
109: pthread_mutex_unlock(&s->sock_mtx);
110: }
111:
112: cli->cli_parent = TASK_ARG(task);
113: cli->cli_fd = c;
114: cli->cli_func = TASK_DATA(task);
115: memcpy(&cli->cli_addr, &sa, sizeof cli->cli_addr);
1.4.4.5 misho 116: AIT_SET_BUFSIZ(&cli->cli_buf[0], 0, AIT_LEN(&s->sock_buf));
117: AIT_SET_BUFSIZ(&cli->cli_buf[1], 0, AIT_LEN(&s->sock_buf));
1.4.4.4 misho 118:
119: schedRead(TASK_ROOT(task), cli->cli_func, cli, cli->cli_fd, TASK_ARG(task), 0);
120: ioUpdTimerSocket(cli);
121: end:
122: schedReadSelf(task);
123: taskExit(task, NULL);
124: }
125:
1.4.4.7 misho 126: static void *
1.4.4.8 ! misho 127: io_bridgeClient(sched_task_t *task)
1.4.4.7 misho 128: {
1.4.4.8 ! misho 129: int c, rlen;
! 130: pid_t pid;
! 131: sockaddr_t sa;
! 132: socklen_t salen = sizeof sa.ss;
! 133: sock_cli_t *cli = NULL;
! 134: sock_t *s = (sock_t*) TASK_ARG(task);
! 135: array_t *args = NULL;
! 136: char **argv = NULL;
! 137:
! 138: if (s->sock_type == SOCK_STREAM) {
! 139: if ((c = accept(TASK_FD(task), &sa.sa, &salen)) == -1) {
! 140: LOGERR;
! 141: goto end;
! 142: }
! 143: } else {
! 144: if ((rlen = recvfrom(TASK_FD(task),
! 145: AIT_GET_BUF(&s->sock_buf), AIT_LEN(&s->sock_buf),
! 146: MSG_PEEK, &sa.sa, &salen)) == -1) {
! 147: LOGERR;
! 148: goto end;
! 149: } else
! 150: c = TASK_FD(task);
! 151: }
! 152:
! 153: cli = e_malloc(sizeof(sock_cli_t));
! 154: if (!cli) {
! 155: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
! 156: if (s->sock_type == SOCK_STREAM)
! 157: close(c);
! 158: goto end;
! 159: } else {
! 160: memset(cli, 0, sizeof(sock_cli_t));
! 161: pthread_mutex_lock(&s->sock_mtx);
! 162: TAILQ_INSERT_TAIL(&s->sock_cli, cli, cli_node);
! 163: pthread_mutex_unlock(&s->sock_mtx);
! 164: }
! 165:
! 166: cli->cli_parent = TASK_ARG(task);
! 167: cli->cli_fd = c;
! 168: strlcpy(cli->cli_cmdline, TASK_DATA(task), sizeof cli->cli_cmdline);
! 169: memcpy(&cli->cli_addr, &sa, sizeof cli->cli_addr);
! 170: AIT_SET_BUFSIZ(&cli->cli_buf[0], 0, AIT_LEN(&s->sock_buf));
! 171: AIT_SET_BUFSIZ(&cli->cli_buf[1], 0, AIT_LEN(&s->sock_buf));
! 172:
! 173: switch ((pid = ioForkPTY(&cli->cli_pty, cli->cli_name, sizeof cli->cli_name,
! 174: NULL, NULL, NULL))) {
! 175: case -1:
! 176: ELIBERR(io);
! 177: break;
! 178: case 0:
! 179: array_Args(cli->cli_cmdline, 0, " \t", &args);
! 180: argv = array_To(args);
! 181: array_Destroy(&args);
! 182:
! 183: execv(*argv, argv);
! 184: break;
! 185: default:
! 186: schedRead(TASK_ROOT(task), io_rxPty, TASK_ARG(task),
! 187: cli->cli_pty, NULL, 0);
! 188: schedRead(TASK_ROOT(task), io_rxNet, TASK_ARG(task),
! 189: cli->cli_fd, NULL, 0);
! 190: ioUpdTimerSocket(cli);
! 191: break;
! 192: }
! 193: end:
! 194: schedReadSelf(task);
1.4.4.7 misho 195: taskExit(task, NULL);
196: }
197:
1.4.4.4 misho 198:
1.2 misho 199: /*
200: * ioInitSocket() - Init socket and allocate resources
201: *
202: * @role = Socket role
203: * @type = Socket type
204: * @proto = Socket protocol
205: * @addr = Bind to address
206: * @port = Bind to port
207: * @buflen = Socket buffer, optional if =0 == BUFSIZ
208: * return: NULL error or !=NULL created socket
209: */
210: sock_t *
211: ioInitSocket(int role, int type, int proto, const char *addr, u_short port, size_t buflen)
212: {
213: sock_t *s = NULL;
214: int n = 1;
215:
216: if (!addr)
217: return NULL;
218:
219: s = e_malloc(sizeof(sock_t));
220: if (!s) {
221: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
222: return NULL;
223: } else
224: memset(s, 0, sizeof(sock_t));
225:
1.3 misho 226: TAILQ_INIT(&s->sock_cli);
227:
1.2 misho 228: s->sock_role = role;
229: s->sock_type = type;
230: s->sock_proto = proto;
231: if (!e_gethostbyname(addr, port, &s->sock_addr)) {
232: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
233: e_free(s);
234: return NULL;
235: } else {
236: buflen = buflen ? buflen : BUFSIZ;
1.4.4.1 misho 237: buflen = E_ALIGN(buflen, 2); /* align buflen length */
1.2 misho 238: AIT_SET_BUFSIZ(&s->sock_buf, 0, buflen);
239: }
240:
241: s->sock_fd = socket(s->sock_addr.sa.sa_family, s->sock_type, s->sock_proto);
242: if (s->sock_fd == -1) {
243: LOGERR;
244: AIT_FREE_VAL(&s->sock_buf);
245: e_free(s);
246: return NULL;
247: }
248: if (setsockopt(s->sock_fd, SOL_SOCKET, SO_SNDBUF, &buflen, sizeof buflen) == -1) {
249: LOGERR;
250: AIT_FREE_VAL(&s->sock_buf);
251: e_free(s);
252: return NULL;
253: }
254: if (setsockopt(s->sock_fd, SOL_SOCKET, SO_RCVBUF, &buflen, sizeof buflen) == -1) {
255: LOGERR;
256: AIT_FREE_VAL(&s->sock_buf);
257: e_free(s);
258: return NULL;
259: }
260: if (setsockopt(s->sock_fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) == -1) {
261: LOGERR;
262: AIT_FREE_VAL(&s->sock_buf);
263: e_free(s);
264: return NULL;
265: }
266: if (bind(s->sock_fd, &s->sock_addr.sa, s->sock_addr.sa.sa_len) == -1) {
267: LOGERR;
268: AIT_FREE_VAL(&s->sock_buf);
269: e_free(s);
270: return NULL;
271: }
272:
1.4.4.1 misho 273: s->sock_root = schedBegin();
274: if (!s->sock_root) {
275: io_SetErr(sched_GetErrno(), "%s", sched_GetError());
276: AIT_FREE_VAL(&s->sock_buf);
277: e_free(s);
278: return NULL;
279: }
280:
1.3 misho 281: pthread_mutex_init(&s->sock_mtx, NULL);
1.2 misho 282: return s;
283: }
284:
285: /*
286: * ioCloseSocket() - Close socket and free resources
287: *
288: * @s = Socket
289: * return: none
290: */
291: void
292: ioCloseSocket(sock_t ** __restrict s)
293: {
1.4.4.4 misho 294: sock_cli_t *cli;
1.3 misho 295:
1.2 misho 296: if (s && *s) {
1.3 misho 297: pthread_mutex_lock(&(*s)->sock_mtx);
298: while ((cli = TAILQ_FIRST(&(*s)->sock_cli))) {
299: TAILQ_REMOVE(&(*s)->sock_cli, cli, cli_node);
1.4.4.4 misho 300:
301: schedCancelby((*s)->sock_root, taskTIMER, CRITERIA_DATLEN,
302: (void*) cli->cli_fd, NULL);
1.4.4.7 misho 303: schedCancelby((*s)->sock_root, taskMAX, CRITERIA_ARG, cli, NULL);
1.4.4.4 misho 304:
305: if ((*s)->sock_type == SOCK_STREAM) {
306: shutdown(cli->cli_fd, SHUT_RDWR);
307: close(cli->cli_fd);
308: }
1.4.4.5 misho 309: AIT_FREE_VAL(&cli->cli_buf[1]);
310: AIT_FREE_VAL(&cli->cli_buf[0]);
1.3 misho 311: e_free(cli);
312: }
313: pthread_mutex_unlock(&(*s)->sock_mtx);
314:
1.2 misho 315: shutdown((*s)->sock_fd, SHUT_RDWR);
316: close((*s)->sock_fd);
317:
318: AIT_FREE_VAL(&(*s)->sock_buf);
1.3 misho 319:
1.4.4.1 misho 320: schedEnd(&(*s)->sock_root);
321:
1.3 misho 322: pthread_mutex_destroy(&(*s)->sock_mtx);
1.2 misho 323: e_free(*s);
324: *s = NULL;
325: }
326: }
327:
328: /*
329: * ioUpSocket() - Setup socket for use
330: *
331: * @s = Socket
332: * @arg = Server role = listen backlog queue and Client role = peer address
1.4.4.1 misho 333: * @timeout = Socket timeout in sec (default -1 infinit)
1.2 misho 334: * return: -1 error or 0 ok
335: */
336: int
1.4.4.1 misho 337: ioUpSocket(sock_t * __restrict s, void *arg, int timeout)
1.2 misho 338: {
339: int ret = 0;
340: sockaddr_t *peer = (sockaddr_t*) arg;
341: uintptr_t backlog = (uintptr_t) arg;
342:
343: if (!s || !arg)
344: return -1;
1.4.4.1 misho 345: else {
346: s->sock_timeout.tv_sec = timeout;
347: s->sock_timeout.tv_nsec = (timeout < 1) ? timeout : 0;
348: schedPolling(s->sock_root, &s->sock_timeout, NULL);
349: }
1.2 misho 350:
351: switch (s->sock_role) {
352: case IO_SOCK_ROLE_CLIENT:
353: memcpy(&s->sock_peer, peer, sizeof s->sock_peer);
354:
355: if (connect(s->sock_fd, &s->sock_peer.sa,
356: s->sock_peer.sa.sa_len) == -1) {
357: LOGERR;
358: return -1;
359: }
360: break;
361: case IO_SOCK_ROLE_SERVER:
362: if (s->sock_type == SOCK_STREAM) {
363: s->sock_backq = backlog;
364:
365: if (listen(s->sock_fd, s->sock_backq) == -1) {
366: LOGERR;
367: return -1;
368: }
369: }
370: break;
371: default:
372: io_SetErr(EINVAL, "Unsupported socket type");
373: return -1;
374: }
375:
376: fcntl(s->sock_fd, F_SETFL, fcntl(s->sock_fd, F_GETFL) | O_NONBLOCK);
377: return ret;
378: }
1.3 misho 379:
380: /*
1.4.4.2 misho 381: * ioUpdTimerSocket() - Update timeout of socket
1.3 misho 382: *
1.4.4.2 misho 383: * @c = Client socket
384: * return: none
1.3 misho 385: */
1.4.4.2 misho 386: void
387: ioUpdTimerSocket(sock_cli_t * __restrict c)
1.3 misho 388: {
1.4.4.2 misho 389: sock_t *s;
1.3 misho 390:
1.4.4.2 misho 391: if (!c)
392: return;
393: else
394: s = c->cli_parent;
1.3 misho 395:
1.4.4.2 misho 396: schedCancelby(s->sock_root, taskTIMER, CRITERIA_DATLEN, (void*) c->cli_fd, NULL);
397: schedTimer(s->sock_root, io_closeClient, c, s->sock_timeout, NULL, c->cli_fd);
398: }
1.3 misho 399:
1.4.4.2 misho 400: /*
1.4.4.6 misho 401: * ioCloseClient() - Close client socket
402: *
403: * @c = Client socket
404: * return: 0 ok or !=0 error
405: */
406: int
407: ioCloseClient(sock_cli_t * __restrict c)
408: {
409: sock_t *s;
410:
411: if (!c)
412: return -1;
413: else
414: s = c->cli_parent;
415:
416: return !schedEvent(s->sock_root, io_closeClient, c, 0, NULL, c->cli_fd);
417: }
418:
419: /*
1.4.4.2 misho 420: * ioLoopSocket() - Start socket scheduler
421: *
422: * @s = Socket
423: * @rcb = Read callback
424: * return: -1 error or return result from scheduler
425: */
426: int
427: ioLoopSocket(sock_t * __restrict s, sched_task_func_t rcb)
428: {
1.4.4.6 misho 429: if (!s || !rcb || s->sock_kill)
430: return -1;
431:
1.4.4.2 misho 432: schedRead(s->sock_root, io_acceptClient, s, s->sock_fd, rcb, 0);
433: return schedRun(s->sock_root, &s->sock_kill);
1.3 misho 434: }
1.4.4.3 misho 435:
436: /*
1.4.4.6 misho 437: * ioBridgeProg2Socket() - Start socket scheduler and bridge program to socket
1.4.4.3 misho 438: *
1.4.4.6 misho 439: * @s = Socket
440: * @prgname = Program name
1.4.4.3 misho 441: * return: 0 ok or !=0 error
442: */
443: int
1.4.4.6 misho 444: ioBridgeProg2Socket(sock_t * __restrict s, const char *prgname)
1.4.4.3 misho 445: {
1.4.4.6 misho 446: if (!s || !prgname || s->sock_kill)
1.4.4.3 misho 447: return -1;
448:
1.4.4.8 ! misho 449: schedRead(s->sock_root, io_bridgeClient, s, s->sock_fd, (void*) prgname, 0);
! 450: return schedRun(s->sock_root, &s->sock_kill);
1.4.4.3 misho 451: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>