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