Annotation of embedaddon/trafshow/session.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1999-2003 Rinet Corp., Novosibirsk, Russia
3: *
4: * Redistribution and use in source forms, with and without modification,
5: * are permitted provided that this entire comment appears intact.
6: *
7: * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
8: */
9:
10: #ifdef HAVE_CONFIG_H
11: #include <config.h>
12: #endif
13:
14: #include <sys/types.h>
15: #include <sys/socket.h>
16: #include <netinet/in.h>
17: #include <fcntl.h>
18: #include <stdlib.h>
19: #include <string.h>
20: #include <unistd.h>
21: #include <errno.h>
22:
23: #include "session.h"
24: #include "events.h" /* just for tv_sub() */
25:
26: #define dprintf(x) /* nope */
27:
28: #ifndef BUF_SIZE
29: #define BUF_SIZE 8192
30: #endif
31: #ifndef MAX_STR_LEN
32: #define MAX_STR_LEN 1500 /* must be vastly smaller then BUF_SIZE */
33: #endif
34:
35: #ifdef O_NONBLOCK
36: #define ASYNC_MODE O_NONBLOCK
37: #elif O_NDELAY
38: #define ASYNC_MODE O_NDELAY
39: #elif FNDELAY
40: #define ASYNC_MODE FNDELAY
41: #elif O_ASYNC
42: #define ASYNC_MODE O_ASYNC
43: #elif
44: #error the fcntl argument to turn ON/OFF non-blocking I/O is unknown
45: #endif
46:
47: static int session_read(SESSION *sd);
48:
49: static SESSION *first_session = 0; /* first network session in table */
50:
51: typedef struct session_binder_ent {
52: void (*notify)(void *arg); /* call it before free */
53: void *arg;
54: struct session_binder_ent *next;
55: } SESSION_BINDER;
56:
57:
58: SESSION *
59: session_open(sock, peer, type)
60: int sock;
61: const struct sockaddr *peer;
62: SessionType type;
63: {
64: SESSION *sd, *prev = 0, *next = 0;
65: static u_long sid = 0;
66:
67: /*
68: * Search for first empty or last session slot.
69: */
70: for (sd = first_session; sd; sd = sd->next) {
71: if (!sd->sid) {
72: next = sd->next;
73: break;
74: }
75: prev = sd;
76: }
77: if (!sd && (sd = (SESSION *)malloc(sizeof(SESSION))) == 0)
78: return 0;
79: memset(sd, 0, sizeof(SESSION));
80:
81: if (++sid == 0) sid++; /* prevent 0 sid */
82: sd->sid = sid;
83: sd->sock = sock;
84: if (peer)
85: memcpy(&sd->peer, peer, sizeof(struct sockaddr));
86: else memset(&sd->peer, 0, sizeof(sd->peer));
87: memset(&sd->from, 0, sizeof(sd->from));
88:
89: sd->type = type;
90:
91: /* make chain */
92: if (next) sd->next = next;
93: else if (prev) prev->next = sd;
94: if (!first_session) first_session = sd;
95:
96: if (session_start(sd) < 0) {
97: sd->sid = 0; /* this slot may be recycled later */
98: sd = 0;
99: }
100: return sd;
101: }
102:
103: int
104: session_start(sd)
105: SESSION *sd;
106: {
107: int af;
108:
109: /* sanity check */
110: if (!sd) {
111: errno = EINVAL;
112: return -1;
113: }
114: errno = EBADF;
115: if (sd->sock != -1 &&
116: (sd->type == PlainFile || socket_peer((struct sockaddr *)&sd->peer, sd->sock) != -1)) {
117: /* already connected for example by accept() */
118:
119: socket_nonblock(sd->sock, 0);
120: if (sd->type == TextStream)
121: socket_keepalive(sd->sock, 1);
122: return 0;
123: }
124:
125: af = sd->peer.ss_family;
126: if (!af) af = AF_INET; /* by default */
127:
128: if (errno == EBADF || errno == ENOTSOCK) {
129: switch (sd->type) {
130: case PlainFile:
131: sd->sock = -1;
132: errno = EINVAL;
133: break;
134: case TextStream:
135: sd->sock = socket(af, SOCK_STREAM, 0);
136: break;
137: case DataSequence:
138: sd->sock = socket(af, SOCK_DGRAM, 0);
139: break;
140: /* XXX other session types would be added here */
141: }
142: if (sd->sock == -1)
143: return -1;
144:
145: errno = ENOTCONN;
146: }
147: if (errno == ENOTCONN) {
148: /*
149: * Make socket `connected' for any type, so error on this
150: * socket will be returned asynchronously without timing out.
151: */
152: socket_nonblock(sd->sock, 1);
153:
154: if (!sd->peer.ss_family) {
155: errno = 0;
156: return 0;
157: }
158:
159: if (connect(sd->sock, (struct sockaddr *)&sd->peer, sizeof(struct sockaddr)) != -1 ||
160: errno == EINPROGRESS)
161: return 0;
162: }
163: /* prevent lost of unused socket */
164: session_stop(sd);
165:
166: return -1;
167: }
168:
169: int
170: session_sock(sd)
171: SESSION *sd;
172: {
173: return (sd ? sd->sock : -1);
174: }
175:
176: unsigned
177: session_settimeout(sd, timeout)
178: SESSION *sd;
179: unsigned timeout;
180: {
181: unsigned prev;
182:
183: if (!sd || !sd->sid) return 0;
184:
185: prev = sd->timeout;
186: sd->timeout = timeout;
187:
188: if (sd->timeout < 1)
189: timerclear(&sd->expire);
190:
191: return prev;
192: }
193:
194: void
195: session_setcallback(sd, connected, read_error, read_data)
196: SESSION *sd;
197: void (*connected)(SESSION *sd);
198: void (*read_error)(SESSION *sd, int error);
199: void (*read_data)(SESSION *sd, const unsigned char *data, int len);
200: {
201: if (sd && sd->sid) {
202: if (connected && sd->type == TextStream) {
203: sd->connected = connected;
204: }
205: if (read_error)
206: sd->read_error = read_error;
207: if (read_data)
208: sd->read_data = read_data;
209: }
210: }
211:
212: void
213: session_setcookie(sd, cookie)
214: SESSION *sd;
215: const void *cookie;
216: {
217: if (sd && sd->sid) sd->cookie = cookie;
218: }
219:
220: const void *
221: session_cookie(sd)
222: SESSION *sd;
223: {
224: return ((sd && sd->sid) ? sd->cookie : 0);
225: }
226:
227: void
228: session_stop(sd)
229: SESSION *sd;
230: {
231: if (!sd) return;
232:
233: if (sd->sock != -1) {
234: close(sd->sock);
235: sd->sock = -1;
236: }
237: if (sd->buf) {
238: free(sd->buf);
239: sd->buf = 0;
240: }
241: timerclear(&sd->expire);
242: }
243:
244: int
245: session_idle(sd)
246: SESSION *sd;
247: {
248: if (!sd || !sd->sid) return -1;
249: return (sd->sock != -1 ? 0 : 1);
250: }
251:
252: int
253: session_bind(sd, notify, arg)
254: SESSION *sd;
255: void (*notify)(void *arg);
256: void *arg;
257: {
258: SESSION_BINDER *curr, *last = 0;
259:
260: if (!sd || !notify || !arg) {
261: errno = EINVAL;
262: return -1;
263: }
264: /* prevent dups and find last */
265: for (curr = sd->sb; curr; curr = curr->next) {
266: if (curr->notify == notify && curr->arg == arg)
267: return 0;
268: last = curr;
269: }
270: if ((curr = (SESSION_BINDER *)malloc(sizeof(SESSION_BINDER))) == 0)
271: return -1;
272: curr->notify = notify;
273: curr->arg = arg;
274: curr->next = 0;
275: if (last)
276: last->next = curr;
277: else sd->sb = curr;
278: return 0;
279: }
280:
281: void
282: session_unbind(sd, notify, arg)
283: SESSION *sd;
284: void (*notify)(void *arg);
285: void *arg;
286: {
287: SESSION_BINDER *curr, *prev, *next;
288:
289: curr = (sd ? sd->sb : 0);
290: prev = 0;
291: while (curr) {
292: if ((!notify && !arg) ||
293: (curr->notify == notify && curr->arg == arg)) {
294: next = curr->next;
295: if (prev)
296: prev->next = next;
297: else sd->sb = next;
298: free(curr);
299: curr = next;
300: } else {
301: prev = curr;
302: curr = curr->next;
303: }
304: }
305: }
306:
307: /*
308: * This function free all memory only when free_sd = 0 else it just reset
309: * session id and does not free memory. The mean of this behaving is to
310: * reuse/recycle session slots without new malloc (avoiding it overhead).
311: */
312: void
313: session_free(free_sd)
314: SESSION *free_sd;
315: {
316: SESSION *sd, *prev, *next;
317: SESSION_BINDER *sb;
318:
319: sd = first_session;
320: prev = next = 0;
321: while (sd) {
322: if (!free_sd || sd == free_sd) {
323: if (!free_sd) {
324: next = sd->next;
325: if (prev)
326: prev->next = next;
327: else first_session = next;
328: }
329:
330: for (sb = sd->sb; sb; sb = sb->next) {
331: if (sb->notify && sb->arg)
332: (*sb->notify)(sb->arg);
333: }
334: session_stop(sd);
335: session_unbind(sd, 0, 0); /* to free all */
336:
337: if (!free_sd) {
338: free(sd);
339: sd = next;
340: continue;
341: }
342: sd->sid = 0; /* this slot may be recycled later */
343: }
344: prev = sd;
345: sd = sd->next;
346: }
347: }
348:
349: SESSION *
350: session_find(peer, type)
351: const struct sockaddr *peer;
352: SessionType type;
353: {
354: SESSION *sd;
355:
356: /* sanity check */
357: if (!peer) return 0;
358:
359: for (sd = first_session; sd; sd = sd->next) {
360: if (!sd->sid || sd->type != type ||
361: sd->peer.ss_family != peer->sa_family)
362: continue;
363:
364: if (peer->sa_family == AF_INET) {
365: struct sockaddr_in *sin = (struct sockaddr_in *)&sd->peer;
366: if (sin->sin_port == ((struct sockaddr_in *)peer)->sin_port &&
367: !memcmp(&sin->sin_addr,
368: &((struct sockaddr_in *)peer)->sin_addr,
369: sizeof(sin->sin_addr)))
370: return sd;
371: }
372: #ifdef INET6
373: else if (peer->sa_family == AF_INET6) {
374: struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&sd->peer;
375: if (sin->sin6_port == ((struct sockaddr_in6 *)peer)->sin6_port &&
376: !memcmp(&sin->sin6_addr,
377: &((struct sockaddr_in6 *)peer)->sin6_addr,
378: sizeof(sin->sin6_addr)))
379: return sd;
380: }
381: #endif
382: }
383: return 0;
384: }
385:
386: int
387: session_send(sd, data, len)
388: SESSION *sd;
389: const unsigned char *data;
390: int len;
391: {
392: int wlen = 0;
393:
394: if (!sd || len < 0) {
395: errno = EINVAL;
396: return -1;
397: }
398: if (!sd->sid || sd->sock == -1) {
399: errno = ENOTCONN;
400: return -1;
401: }
402: if (data) {
403: if (sd->type == PlainFile) {
404: if (len) wlen = write(sd->sock, data, len);
405:
406: } else if (sd->type == TextStream) {
407: char buf[BUF_SIZE];
408:
409: if (!sd->peer.ss_family) {
410: errno = ENOTCONN;
411: return -1;
412: }
413: if (len > sizeof(buf)-2) len = sizeof(buf)-2;
414: if (len) memcpy(buf, data, len);
415: if (!len || buf[len-1] != '\n') {
416: buf[len++] = '\r';
417: buf[len++] = '\n';
418: }
419: wlen = write(sd->sock, buf, len);
420:
421: } else if (sd->type == DataSequence) {
422:
423: if (!sd->peer.ss_family) {
424: errno = ENOTCONN;
425: return -1;
426: }
427: if (len) wlen = send(sd->sock, data, len, 0);
428:
429: } else { /* XXX other session types must be added here */
430: wlen = -1;
431: errno = ESOCKTNOSUPPORT;
432: }
433: }
434: if (wlen == -1) {
435: if (errno == EAGAIN || errno == EINPROGRESS) {
436: errno = 0;
437: wlen = 0;
438: } else if (sd->read_error) {
439: (*sd->read_error)(sd, errno);
440: return wlen;
441: }
442: }
443: if (sd->timeout > 0) {
444: gettimeofday(&sd->expire, 0);
445: sd->expire.tv_sec += sd->timeout;
446: }
447: return wlen;
448: }
449:
450: static int
451: session_read(sd)
452: SESSION *sd;
453: {
454: int rlen = 0, rest = 0;
455: char *cp, *line, buf[BUF_SIZE];
456:
457: if (!sd) {
458: errno = EINVAL;
459: return -1;
460: }
461: if (!sd->sid || sd->sock == -1) {
462: errno = ENOTCONN;
463: return -1;
464: }
465: buf[0] = '\0';
466:
467: if (sd->type == PlainFile) {
468: rlen = read(sd->sock, buf, sizeof(buf));
469:
470: } else if (sd->type == TextStream) {
471: if (sd->buf) { /* previous line was truncated */
472: rest = strlen(strcpy(buf, sd->buf));
473: free(sd->buf);
474: sd->buf = 0;
475: }
476: rlen = read(sd->sock, &buf[rest], (sizeof(buf)-1) - rest);
477:
478: } else if (sd->type == DataSequence) {
479: struct sockaddr from;
480: socklen_t slen = sizeof(from);
481:
482: rlen = recvfrom(sd->sock, buf, sizeof(buf), 0, &from, &slen);
483: if (rlen != -1) {
484: /* just for sanity */
485: if (slen < sizeof(struct sockaddr_in) ||
486: slen > sizeof(struct sockaddr))
487: return 0; /* should not happen */
488:
489: if (sd->peer.ss_family &&
490: sd->peer.ss_family != from.sa_family)
491: return 0; /* bad family */
492:
493: /* save packet from */
494: memcpy(&sd->from, &from, slen);
495: } else memset(&sd->from, 0, sizeof(sd->from));
496:
497: } else { /* XXX other session types must be added here */
498: errno = ESOCKTNOSUPPORT;
499: return -1;
500: }
501:
502: if (rlen < 1) {
503: if (!rlen || !errno)
504: errno = ECONNRESET;
505: return -1;
506: }
507:
508: if (sd->type == PlainFile || sd->type == DataSequence) {
509: if (!sd->sid || sd->sock == -1)
510: return 0;
511: if (sd->read_data)
512: (*sd->read_data)(sd, (u_char *)buf, rlen);
513:
514: } else { /* TextStream */
515: buf[rest + rlen] = '\0';
516: for (cp = buf; (line = strchr(cp, '\n')) != 0; cp = line) {
517: if (line > cp && line[-1] == '\r') line[-1] = '\0';
518: *line++ = '\0';
519: if (!sd->sid || sd->sock == -1)
520: return 0;
521: if (sd->read_data) {
522: rest = strlen(cp);
523: if (rest > MAX_STR_LEN) {
524: errno = EMSGSIZE;
525: return -1;
526: }
527: (*sd->read_data)(sd, (u_char *)cp, rest);
528: }
529: }
530: if (cp && *cp) { /* truncated line, save it for next read */
531: if (strlen(cp) > MAX_STR_LEN) {
532: errno = EMSGSIZE;
533: return -1;
534: }
535: sd->buf = strdup(cp);
536: }
537: }
538: return rlen;
539: }
540:
541: int
542: session_select(nfds, readfds, writefds, timeout, block)
543: int *nfds;
544: fd_set *readfds, *writefds;
545: struct timeval *timeout;
546: int *block;
547: {
548: SESSION *sd;
549: struct timeval earliest, now;
550: int active = 0, pending = 0;
551:
552: timerclear(&earliest);
553:
554: /*
555: * For each request outstanding, add it's socket to the readfds,
556: * and if it is the earliest timeout to expire, mark it as lowest.
557: */
558: for (sd = first_session; sd; sd = sd->next) {
559: if (!sd->sid || sd->sock == -1) {
560: if (sd->sock != -1) /* lost session? free socket */
561: session_stop(sd);
562: continue;
563: }
564:
565: active++;
566: if (sd->sock + 1 > *nfds)
567: *nfds = sd->sock + 1;
568:
569: if (!sd->connected) {
570: FD_SET(sd->sock, readfds);
571:
572: dprintf(("session_select: sock %d set for read", sd->sock));
573: } else {
574: FD_SET(sd->sock, writefds);
575:
576: dprintf(("session_select: sock %d set for write", sd->sock));
577: }
578:
579: if (timerisset(&sd->expire)) {
580: pending++;
581: if (!timerisset(&earliest) ||
582: timercmp(&sd->expire, &earliest, <))
583: earliest = sd->expire;
584: }
585: }
586:
587: /*dprintf(("session_select: active=%d pending=%d", active, pending));*/
588:
589: if (!pending)
590: return active;
591:
592: /*
593: * Transforms earliest from an absolute time into a delta time, the
594: * time left until the select should timeout.
595: */
596: gettimeofday(&now, 0);
597: tv_sub(&earliest, &now);
598:
599: /* if it was blocking before or our delta time is less, reset timeout */
600: if (*block || timercmp(&earliest, timeout, <)) {
601: *timeout = earliest;
602: *block = 0;
603: }
604: return active;
605: }
606:
607: /*
608: * Checks to see if any of the fd's set in the readfds belong to a session.
609: */
610: void
611: session_operate(readfds, writefds)
612: fd_set *readfds, *writefds;
613: {
614: SESSION *sd;
615: int try_conn, error;
616:
617: for (sd = first_session; sd; sd = sd->next) {
618: if (!sd->sid || sd->sock == -1)
619: continue;
620:
621: try_conn = (sd->connected != 0);
622:
623: if (!try_conn && FD_ISSET(sd->sock, readfds)) {
624:
625: dprintf(("session_operate: sock %d ready to read", sd->sock));
626:
627: if (sd->type == PlainFile)
628: error = 0;
629: else error = socket_error(sd->sock);
630:
631: if (!error && session_read(sd) < 0)
632: error = errno;
633: if (error && sd->sid && sd->read_error)
634: (*sd->read_error)(sd, error);
635: }
636:
637: if (try_conn && FD_ISSET(sd->sock, writefds)) {
638:
639: dprintf(("session_operate: sock %d ready to write", sd->sock));
640:
641: error = socket_error(sd->sock);
642: if (!error) {
643: socket_peer((struct sockaddr *)&sd->peer, sd->sock);
644: socket_nonblock(sd->sock, 0);
645: if (sd->type == TextStream)
646: socket_keepalive(sd->sock, 1);
647: if (sd->sid && sd->connected)
648: (*sd->connected)(sd);
649: sd->connected = 0; /* fire a shot only once! */
650: } else if (sd->sid && sd->read_error)
651: (*sd->read_error)(sd, error);
652: }
653: }
654: }
655:
656: /*
657: * Checks to see if any of the sessions have an outstanding request
658: * that has timed out.
659: */
660: void
661: session_timeout()
662: {
663: SESSION *sd;
664: struct timeval now;
665:
666: gettimeofday(&now, 0);
667:
668: for (sd = first_session; sd; sd = sd->next) {
669: if (!sd->sid || sd->sock == -1)
670: continue;
671:
672: if (timerisset(&sd->expire) && timercmp(&sd->expire, &now, <)) {
673: if (sd->read_error) (*sd->read_error)(sd, ETIMEDOUT);
674: }
675: }
676: }
677:
678: /*
679: * Return session peer pointer.
680: */
681: const struct sockaddr *
682: session_peer(sd)
683: SESSION *sd;
684: {
685: return ((sd && sd->peer.ss_family) ? (struct sockaddr *)&sd->peer : 0);
686: }
687:
688: /*
689: * Return session from pointer.
690: */
691: const struct sockaddr *
692: session_from(sd)
693: SESSION *sd;
694: {
695: return ((sd && sd->from.ss_family) ? (struct sockaddr *)&sd->from : 0);
696: }
697:
698: /*
699: * Return connected socket peer ip address and port.
700: */
701: int
702: socket_peer(peer, sock)
703: struct sockaddr *peer;
704: int sock;
705: {
706: socklen_t arglen;
707:
708: if (!peer) {
709: errno = EINVAL;
710: return -1;
711: }
712: arglen = sizeof(struct sockaddr);
713: return getpeername(sock, peer, &arglen);
714: }
715:
716: /*
717: * Return socket name ip address and port.
718: */
719: int
720: socket_name(name, sock)
721: struct sockaddr *name;
722: int sock;
723: {
724: socklen_t arglen;
725:
726: if (!name) {
727: errno = EINVAL;
728: return -1;
729: }
730: arglen = sizeof(*name);
731: return getsockname(sock, name, &arglen);
732: }
733:
734: /*
735: * Return socket error (like errno) in the session or 0 if no errors.
736: */
737: int
738: socket_error(sock)
739: int sock;
740: {
741: int argbuf;
742: socklen_t arglen;
743: struct sockaddr peer;
744:
745: arglen = sizeof(argbuf);
746: if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &argbuf, &arglen) < 0)
747: return errno;
748: if (argbuf)
749: return argbuf;
750:
751: arglen = sizeof(argbuf);
752: if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &argbuf, &arglen) < 0)
753: return errno;
754: if (argbuf == SOCK_STREAM) {
755: arglen = sizeof(peer);
756: if (getpeername(sock, &peer, &arglen) < 0)
757: return errno;
758: }
759: return 0;
760: }
761:
762: /*
763: * Make socket blocked or non-blocked for sync/async I/O.
764: */
765: int
766: socket_nonblock(sock, on)
767: int sock;
768: int on; /* boolean */
769: {
770: int mode;
771: int prev; /* boolean */
772:
773: /* get current value of I/O mode */
774: if ((mode = fcntl(sock, F_GETFL, 0)) < 0)
775: return -1;
776:
777: prev = (mode & ASYNC_MODE) != 0;
778: if (on != prev) {
779: if (on) mode |= ASYNC_MODE;
780: else mode &= ~ASYNC_MODE;
781: if (fcntl(sock, F_SETFL, mode))
782: return -1;
783: }
784: return prev;
785: }
786:
787: int
788: socket_keepalive(sock, on)
789: int sock, on;
790: {
791: #ifdef SO_KEEPALIVE
792: int curr = 0;
793: socklen_t slen = sizeof(curr);
794: if (getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &curr, &slen) < 0)
795: return -1;
796:
797: curr = (curr != 0);
798: if (on != curr) {
799: if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0)
800: return -1;
801: }
802: return 0;
803: #else
804: errno = ESOCKTNOSUPPORT;
805: return -1;
806: #endif
807: }
808:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>