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>