Annotation of sbbs/src/xpdev/sockwrap.c, revision 1.1.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.