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