Annotation of sbbs/src/xpdev/sockwrap.c, revision 1.1

1.1     ! root        1: /* sockwrap.c */
        !             2: 
        !             3: /* Berkley/WinSock socket API wrappers */
        !             4: 
        !             5: /* $Id: sockwrap.c,v 1.32 2006/05/09 21:02:55 deuce Exp $ */
        !             6: 
        !             7: /****************************************************************************
        !             8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
        !             9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
        !            10:  *                                                                                                                                                     *
        !            11:  * Copyright 2005 Rob Swindell - http://www.synchro.net/copyright.html         *
        !            12:  *                                                                                                                                                     *
        !            13:  * This library is free software; you can redistribute it and/or                       *
        !            14:  * modify it under the terms of the GNU Lesser General Public License          *
        !            15:  * as published by the Free Software Foundation; either version 2                      *
        !            16:  * of the License, or (at your option) any later version.                                      *
        !            17:  * See the GNU Lesser General Public License for more details: lgpl.txt or     *
        !            18:  * http://www.fsf.org/copyleft/lesser.html                                                                     *
        !            19:  *                                                                                                                                                     *
        !            20:  * Anonymous FTP access to the most recent released source is available at     *
        !            21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
        !            22:  *                                                                                                                                                     *
        !            23:  * Anonymous CVS access to the development source and modification history     *
        !            24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
        !            25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
        !            26:  *     (just hit return, no password is necessary)                                                     *
        !            27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
        !            28:  *                                                                                                                                                     *
        !            29:  * For Synchronet coding style and modification guidelines, see                                *
        !            30:  * http://www.synchro.net/source.html                                                                          *
        !            31:  *                                                                                                                                                     *
        !            32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
        !            33:  * format) via e-mail to [email protected]                                                                      *
        !            34:  *                                                                                                                                                     *
        !            35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
        !            36:  ****************************************************************************/
        !            37: 
        !            38: #include <stdlib.h>            /* alloca/free on FreeBSD */
        !            39: #include <string.h>            /* bzero (for FD_ZERO) on FreeBSD */
        !            40: #include <errno.h>             /* ENOMEM */
        !            41: #include <stdio.h>             /* SEEK_SET */
        !            42: #include <string.h>
        !            43: #if defined(_WIN32)
        !            44:  #include <malloc.h>   /* alloca() on Win32 */
        !            45: #endif
        !            46: 
        !            47: #include "genwrap.h"   /* SLEEP */
        !            48: #include "gen_defs.h"  /* BOOL/LOG_WARNING */
        !            49: #include "sockwrap.h"  /* sendsocket */
        !            50: #include "filewrap.h"  /* filelength */
        !            51: 
        !            52: static socket_option_t socket_options[] = {
        !            53:        { "TYPE",                               0,                              SOL_SOCKET,             SO_TYPE                         },
        !            54:        { "ERROR",                              0,                              SOL_SOCKET,             SO_ERROR                        },
        !            55:        { "DEBUG",                              0,                              SOL_SOCKET,             SO_DEBUG                        },
        !            56:        { "LINGER",                             SOCK_STREAM,    SOL_SOCKET,             SO_LINGER                       },
        !            57:        { "SNDBUF",                             0,                              SOL_SOCKET,             SO_SNDBUF                       },
        !            58:        { "RCVBUF",                             0,                              SOL_SOCKET,             SO_RCVBUF                       },
        !            59: 
        !            60: #ifndef _WINSOCKAPI_   /* Defined, but not supported, by WinSock */
        !            61:        { "SNDLOWAT",                   0,                              SOL_SOCKET,             SO_SNDLOWAT                     },
        !            62:        { "RCVLOWAT",                   0,                              SOL_SOCKET,             SO_RCVLOWAT                     },
        !            63:        { "SNDTIMEO",                   0,                              SOL_SOCKET,             SO_SNDTIMEO                     },
        !            64:        { "RCVTIMEO",                   0,                              SOL_SOCKET,             SO_RCVTIMEO                     },
        !            65: #ifdef SO_USELOOPBACK  /* SunOS */
        !            66:        { "USELOOPBACK",                0,                              SOL_SOCKET,             SO_USELOOPBACK          },
        !            67: #endif
        !            68: #endif
        !            69: 
        !            70:        { "REUSEADDR",                  0,                              SOL_SOCKET,             SO_REUSEADDR            },      
        !            71:        { "KEEPALIVE",                  SOCK_STREAM,    SOL_SOCKET,             SO_KEEPALIVE            },
        !            72:        { "DONTROUTE",                  0,                              SOL_SOCKET,             SO_DONTROUTE            },
        !            73:        { "BROADCAST",                  SOCK_DGRAM,             SOL_SOCKET,             SO_BROADCAST            },
        !            74:        { "OOBINLINE",                  SOCK_STREAM,    SOL_SOCKET,             SO_OOBINLINE            },
        !            75: 
        !            76: #ifdef SO_ACCEPTCONN                                                                                   
        !            77:        { "ACCEPTCONN",                 SOCK_STREAM,    SOL_SOCKET,             SO_ACCEPTCONN           },
        !            78: #endif
        !            79: #ifdef SO_PRIORITY             /* Linux */
        !            80:        { "PRIORITY",                   0,                              SOL_SOCKET,             SO_PRIORITY                     },
        !            81: #endif
        !            82: #ifdef SO_NO_CHECK             /* Linux */
        !            83:        { "NO_CHECK",                   0,                              SOL_SOCKET,             SO_NO_CHECK                     },
        !            84: #endif
        !            85: #ifdef SO_PROTOTYPE            /* SunOS */
        !            86:        { "PROTOTYPE",                  0,                              SOL_SOCKET,             SO_PROTOTYPE            },
        !            87: #endif
        !            88: #ifdef SO_MAX_MSG_SIZE /* WinSock2 */
        !            89:        { "MAX_MSG_SIZE",               SOCK_DGRAM,             SOL_SOCKET,             SO_MAX_MSG_SIZE         },
        !            90: #endif
        !            91: #ifdef SO_CONNECT_TIME /* WinSock2 */
        !            92:        { "CONNECT_TIME",               SOCK_STREAM,    SOL_SOCKET,             SO_CONNECT_TIME         },
        !            93: #endif
        !            94: 
        !            95:        /* IPPROTO-level socket options */
        !            96:        { "TCP_NODELAY",                SOCK_STREAM,    IPPROTO_TCP,    TCP_NODELAY                     },
        !            97:        /* The following are platform-specific */                                       
        !            98: #ifdef TCP_MAXSEG                                                                                      
        !            99:        { "TCP_MAXSEG",                 SOCK_STREAM,    IPPROTO_TCP,    TCP_MAXSEG                      },
        !           100: #endif                                                                                                                 
        !           101: #ifdef TCP_CORK                                                                                                        
        !           102:        { "TCP_CORK",                   SOCK_STREAM,    IPPROTO_TCP,    TCP_CORK                        },
        !           103: #endif                                                                                                                 
        !           104: #ifdef TCP_KEEPIDLE                                                                                            
        !           105:        { "TCP_KEEPIDLE",               SOCK_STREAM,    IPPROTO_TCP,    TCP_KEEPIDLE            },
        !           106: #endif                                                                                                                 
        !           107: #ifdef TCP_KEEPINTVL                                                                                   
        !           108:        { "TCP_KEEPINTVL",              SOCK_STREAM,    IPPROTO_TCP,    TCP_KEEPINTVL           },
        !           109: #endif                                                                                                                 
        !           110: #ifdef TCP_KEEPCNT                                                                                             
        !           111:        { "TCP_KEEPCNT",                SOCK_STREAM,    IPPROTO_TCP,    TCP_KEEPCNT                     },
        !           112: #endif                                                                                                                 
        !           113: #ifdef TCP_KEEPALIVE   /* SunOS */
        !           114:        { "TCP_KEEPALIVE",              SOCK_STREAM,    IPPROTO_TCP,    TCP_KEEPALIVE           },
        !           115: #endif                                                                                                                 
        !           116: #ifdef TCP_SYNCNT                                                                                              
        !           117:        { "TCP_SYNCNT",                 SOCK_STREAM,    IPPROTO_TCP,    TCP_SYNCNT                      },
        !           118: #endif                                                                                                                 
        !           119: #ifdef TCP_LINGER2                                                                                             
        !           120:        { "TCP_LINGER2",                SOCK_STREAM,    IPPROTO_TCP,    TCP_LINGER2                     },
        !           121: #endif                                                                                                         
        !           122: #ifdef TCP_DEFER_ACCEPT                                                                                
        !           123:        { "TCP_DEFER_ACCEPT",   SOCK_STREAM,    IPPROTO_TCP,    TCP_DEFER_ACCEPT        },
        !           124: #endif                                                                                                                 
        !           125: #ifdef TCP_WINDOW_CLAMP                                                                                        
        !           126:        { "TCP_WINDOW_CLAMP",   SOCK_STREAM,    IPPROTO_TCP,    TCP_WINDOW_CLAMP        },
        !           127: #endif                                                                                                         
        !           128: #ifdef TCP_QUICKACK                                                                                    
        !           129:        { "TCP_QUICKACK",               SOCK_STREAM,    IPPROTO_TCP,    TCP_QUICKACK            },
        !           130: #endif                                         
        !           131: #ifdef TCP_NOPUSH                      
        !           132:        { "TCP_NOPUSH",                 SOCK_STREAM,    IPPROTO_TCP,    TCP_NOPUSH                      },
        !           133: #endif                                         
        !           134: #ifdef TCP_NOOPT                       
        !           135:        { "TCP_NOOPT",                  SOCK_STREAM,    IPPROTO_TCP,    TCP_NOOPT                       },
        !           136: #endif
        !           137:        { NULL }
        !           138: };
        !           139: 
        !           140: int getSocketOptionByName(const char* name, int* level)
        !           141: {
        !           142:        int i;
        !           143: 
        !           144:        if(level!=NULL)
        !           145:                *level=SOL_SOCKET;      /* default option level */
        !           146:        for(i=0;socket_options[i].name;i++) {
        !           147:                if(stricmp(name,socket_options[i].name)==0) {
        !           148:                        if(level!=NULL)
        !           149:                                *level = socket_options[i].level;
        !           150:                        return(socket_options[i].value);
        !           151:                }
        !           152:        }
        !           153:        if(!isdigit(*name))     /* unknown option name */
        !           154:                return(-1);
        !           155:        return(strtol(name,NULL,0));
        !           156: }
        !           157: 
        !           158: socket_option_t* getSocketOptionList(void)
        !           159: {
        !           160:        return(socket_options);
        !           161: }
        !           162: 
        !           163: int sendfilesocket(int sock, int file, long *offset, long count)
        !           164: {
        !           165:        char    buf[1024*16];
        !           166:        long    len;
        !           167:        int             rd;
        !           168:        int             wr=0;
        !           169:        int             total=0;
        !           170:        int             i;
        !           171: 
        !           172: /* sendfile() on Linux may or may not work with non-blocking sockets ToDo */
        !           173:        len=filelength(file);
        !           174: 
        !           175:        if(offset!=NULL)
        !           176:                if(lseek(file,*offset,SEEK_SET)<0)
        !           177:                        return(-1);
        !           178: 
        !           179:        if(count<1 || count>len) {
        !           180:                count=len;
        !           181:                count-=tell(file);              /* don't try to read beyond EOF */
        !           182:        }
        !           183: #if USE_SENDFILE
        !           184:        while((i=sendfile(file,sock,(offset==NULL?0:*offset)+total,count-total,NULL,&wr,0))==-1 && errno==EAGAIN)  {
        !           185:                total+=wr;
        !           186:                SLEEP(1);
        !           187:        }
        !           188:        if(i==0)
        !           189:                return((int)count);
        !           190: #endif
        !           191: 
        !           192:        if(count<0) {
        !           193:                errno=EINVAL;
        !           194:                return(-1);
        !           195:        }
        !           196: 
        !           197:        while(total<count) {
        !           198:                rd=read(file,buf,sizeof(buf));
        !           199:                if(rd==-1)
        !           200:                        return(-1);
        !           201:                if(rd==0)
        !           202:                        break;
        !           203:                for(i=wr=0;i<rd;i+=wr) {
        !           204:                        wr=sendsocket(sock,buf+i,rd-i);
        !           205:                        if(wr>0)
        !           206:                                continue;
        !           207:                        if(wr==SOCKET_ERROR && ERROR_VALUE==EWOULDBLOCK) {
        !           208:                                wr=0;
        !           209:                                SLEEP(1);
        !           210:                                continue;
        !           211:                        }
        !           212:                        return(wr);
        !           213:                }
        !           214:                if(i!=rd)
        !           215:                        return(-1);
        !           216:                total+=rd;
        !           217:        }
        !           218: 
        !           219:        if(offset!=NULL)
        !           220:                (*offset)+=total;
        !           221: 
        !           222:        return(total);
        !           223: }
        !           224: 
        !           225: int recvfilesocket(int sock, int file, long *offset, long count)
        !           226: {
        !           227:        /* Writes a file from a socket -
        !           228:         *
        !           229:         * sock         - Socket to read from
        !           230:         * file         - File descriptior to write to
        !           231:         *                              MUST be open and writeable
        !           232:         * offset       - pointer to file offset to start writing at
        !           233:         *                              is set to offset writing STOPPED
        !           234:         *                              on return
        !           235:         * count        - number of bytes to read/write
        !           236:         *
        !           237:         * returns -1 if an error occurse, otherwise
        !           238:         * returns number ob bytes written and sets offset
        !           239:         * to the new offset
        !           240:         */
        !           241:         
        !           242:        char*   buf;
        !           243:        int             rd;
        !           244:        int             wr;
        !           245: 
        !           246:        if(count<1) {
        !           247:                errno=ERANGE;
        !           248:                return(-1);
        !           249:        }
        !           250:                
        !           251:        if((buf=(char*)alloca(count))==NULL) {
        !           252:                errno=ENOMEM;
        !           253:                return(-1);
        !           254:        }
        !           255: 
        !           256:        if(offset!=NULL)
        !           257:                if(lseek(file,*offset,SEEK_SET)<0)
        !           258:                        return(-1);
        !           259: 
        !           260:        rd=read(sock,buf,count);
        !           261:        if(rd!=count)
        !           262:                return(-1);
        !           263: 
        !           264:        wr=write(file,buf,rd);
        !           265: 
        !           266:        if(offset!=NULL)
        !           267:                (*offset)+=wr;
        !           268: 
        !           269:        return(wr);
        !           270: }
        !           271: 
        !           272: 
        !           273: /* Return true if connected, optionally sets *rd_p to true if read data available */
        !           274: BOOL socket_check(SOCKET sock, BOOL* rd_p, BOOL* wr_p, DWORD timeout)
        !           275: {
        !           276:        char    ch;
        !           277:        int             i,rd;
        !           278:        fd_set  rd_set;
        !           279:        fd_set* rd_set_p=&rd_set;
        !           280:        fd_set  wr_set;
        !           281:        fd_set* wr_set_p=NULL;
        !           282:        struct  timeval tv;
        !           283: 
        !           284:        if(rd_p!=NULL)
        !           285:                *rd_p=FALSE;
        !           286: 
        !           287:        if(wr_p!=NULL)
        !           288:                *wr_p=FALSE;
        !           289: 
        !           290:        if(sock==INVALID_SOCKET)
        !           291:                return(FALSE);
        !           292: 
        !           293:        FD_ZERO(&rd_set);
        !           294:        FD_SET(sock,&rd_set);
        !           295:        if(wr_p!=NULL) {
        !           296:                wr_set_p=&wr_set;
        !           297:                FD_ZERO(wr_set_p);
        !           298:                FD_SET(sock,wr_set_p);
        !           299:                if(rd_p==NULL)
        !           300:                        rd_set_p=NULL;
        !           301:        }
        !           302: 
        !           303:        /* Convert timeout from ms to sec/usec */
        !           304:        tv.tv_sec=timeout/1000;
        !           305:        tv.tv_usec=(timeout%1000)*1000;
        !           306: 
        !           307:        i=select(sock+1,rd_set_p,wr_set_p,NULL,&tv);
        !           308:        if(i==SOCKET_ERROR)
        !           309:                return(FALSE);
        !           310: 
        !           311:        if(i==0) 
        !           312:                return(TRUE);
        !           313: 
        !           314:        if(wr_p!=NULL && FD_ISSET(sock,wr_set_p)) {
        !           315:                *wr_p=TRUE;
        !           316:                if(i==1)
        !           317:                        return(TRUE);
        !           318:        }
        !           319: 
        !           320:        if(rd_p !=NULL || wr_p==NULL)  {
        !           321:                rd=recv(sock,&ch,1,MSG_PEEK);
        !           322:                if(rd==1 
        !           323:                        || (rd==SOCKET_ERROR && ERROR_VALUE==EMSGSIZE)) {
        !           324:                        if(rd_p!=NULL)
        !           325:                                *rd_p=TRUE;
        !           326:                        return(TRUE);
        !           327:                }
        !           328:        }
        !           329: 
        !           330:        return(FALSE);
        !           331: }
        !           332: 
        !           333: int retry_bind(SOCKET s, const struct sockaddr *addr, socklen_t addrlen
        !           334:                           ,uint retries, uint wait_secs
        !           335:                           ,const char* prot
        !           336:                           ,int (*lprintf)(int level, char *fmt, ...))
        !           337: {
        !           338:        char    port_str[128];
        !           339:        int             result=-1;
        !           340:        uint    i;
        !           341: 
        !           342:        if(addr->sa_family==AF_INET)
        !           343:                SAFEPRINTF(port_str," to port %u",ntohs(((SOCKADDR_IN *)(addr))->sin_port)); 
        !           344:        else
        !           345:                port_str[0]=0;
        !           346:        for(i=0;i<=retries;i++) {
        !           347:                if((result=bind(s,addr,addrlen))==0)
        !           348:                        break;
        !           349:                if(lprintf!=NULL)
        !           350:                        lprintf(i<retries ? LOG_WARNING:LOG_ERR
        !           351:                                ,"%04d !ERROR %d binding %s socket%s", s, ERROR_VALUE, prot, port_str);
        !           352:                if(i<retries) {
        !           353:                        if(lprintf!=NULL)
        !           354:                                lprintf(LOG_WARNING,"%04d Will retry in %u seconds (%u of %u)"
        !           355:                                        ,s, wait_secs, i+1, retries);
        !           356:                        SLEEP(wait_secs*1000);
        !           357:                }
        !           358:        }
        !           359:        return(result);
        !           360: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.