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

1.1       root        1: /* sockwrap.c */
                      2: 
                      3: /* Berkley/WinSock socket API wrappers */
                      4: 
1.1.1.2 ! root        5: /* $Id: sockwrap.c,v 1.42 2011/09/19 03:08:56 rswindell Exp $ */
1.1       root        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:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       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: 
1.1.1.2 ! root       38: #include <ctype.h>             /* isdigit */
1.1       root       39: #include <stdlib.h>            /* alloca/free on FreeBSD */
                     40: #include <string.h>            /* bzero (for FD_ZERO) on FreeBSD */
                     41: #include <errno.h>             /* ENOMEM */
                     42: #include <stdio.h>             /* SEEK_SET */
                     43: #include <string.h>
                     44: #if defined(_WIN32)
                     45:  #include <malloc.h>   /* alloca() on Win32 */
                     46: #endif
                     47: 
                     48: #include "genwrap.h"   /* SLEEP */
                     49: #include "gen_defs.h"  /* BOOL/LOG_WARNING */
                     50: #include "sockwrap.h"  /* sendsocket */
                     51: #include "filewrap.h"  /* filelength */
                     52: 
                     53: static socket_option_t socket_options[] = {
                     54:        { "TYPE",                               0,                              SOL_SOCKET,             SO_TYPE                         },
                     55:        { "ERROR",                              0,                              SOL_SOCKET,             SO_ERROR                        },
                     56:        { "DEBUG",                              0,                              SOL_SOCKET,             SO_DEBUG                        },
                     57:        { "LINGER",                             SOCK_STREAM,    SOL_SOCKET,             SO_LINGER                       },
                     58:        { "SNDBUF",                             0,                              SOL_SOCKET,             SO_SNDBUF                       },
                     59:        { "RCVBUF",                             0,                              SOL_SOCKET,             SO_RCVBUF                       },
                     60: 
                     61: #ifndef _WINSOCKAPI_   /* Defined, but not supported, by WinSock */
                     62:        { "SNDLOWAT",                   0,                              SOL_SOCKET,             SO_SNDLOWAT                     },
                     63:        { "RCVLOWAT",                   0,                              SOL_SOCKET,             SO_RCVLOWAT                     },
                     64:        { "SNDTIMEO",                   0,                              SOL_SOCKET,             SO_SNDTIMEO                     },
                     65:        { "RCVTIMEO",                   0,                              SOL_SOCKET,             SO_RCVTIMEO                     },
                     66: #ifdef SO_USELOOPBACK  /* SunOS */
                     67:        { "USELOOPBACK",                0,                              SOL_SOCKET,             SO_USELOOPBACK          },
                     68: #endif
                     69: #endif
                     70: 
                     71:        { "REUSEADDR",                  0,                              SOL_SOCKET,             SO_REUSEADDR            },      
1.1.1.2 ! root       72: #ifdef SO_REUSEPORT    /* BSD */
        !            73:        { "REUSEPORT",                  0,                              SOL_SOCKET,             SO_REUSEPORT            },      
        !            74: #endif
1.1       root       75:        { "KEEPALIVE",                  SOCK_STREAM,    SOL_SOCKET,             SO_KEEPALIVE            },
                     76:        { "DONTROUTE",                  0,                              SOL_SOCKET,             SO_DONTROUTE            },
                     77:        { "BROADCAST",                  SOCK_DGRAM,             SOL_SOCKET,             SO_BROADCAST            },
                     78:        { "OOBINLINE",                  SOCK_STREAM,    SOL_SOCKET,             SO_OOBINLINE            },
                     79: 
                     80: #ifdef SO_ACCEPTCONN                                                                                   
                     81:        { "ACCEPTCONN",                 SOCK_STREAM,    SOL_SOCKET,             SO_ACCEPTCONN           },
                     82: #endif
                     83: #ifdef SO_PRIORITY             /* Linux */
                     84:        { "PRIORITY",                   0,                              SOL_SOCKET,             SO_PRIORITY                     },
                     85: #endif
                     86: #ifdef SO_NO_CHECK             /* Linux */
                     87:        { "NO_CHECK",                   0,                              SOL_SOCKET,             SO_NO_CHECK                     },
                     88: #endif
                     89: #ifdef SO_PROTOTYPE            /* SunOS */
                     90:        { "PROTOTYPE",                  0,                              SOL_SOCKET,             SO_PROTOTYPE            },
                     91: #endif
                     92: #ifdef SO_MAX_MSG_SIZE /* WinSock2 */
                     93:        { "MAX_MSG_SIZE",               SOCK_DGRAM,             SOL_SOCKET,             SO_MAX_MSG_SIZE         },
                     94: #endif
                     95: #ifdef SO_CONNECT_TIME /* WinSock2 */
                     96:        { "CONNECT_TIME",               SOCK_STREAM,    SOL_SOCKET,             SO_CONNECT_TIME         },
                     97: #endif
                     98: 
                     99:        /* IPPROTO-level socket options */
                    100:        { "TCP_NODELAY",                SOCK_STREAM,    IPPROTO_TCP,    TCP_NODELAY                     },
                    101:        /* The following are platform-specific */                                       
                    102: #ifdef TCP_MAXSEG                                                                                      
                    103:        { "TCP_MAXSEG",                 SOCK_STREAM,    IPPROTO_TCP,    TCP_MAXSEG                      },
                    104: #endif                                                                                                                 
                    105: #ifdef TCP_CORK                                                                                                        
                    106:        { "TCP_CORK",                   SOCK_STREAM,    IPPROTO_TCP,    TCP_CORK                        },
                    107: #endif                                                                                                                 
                    108: #ifdef TCP_KEEPIDLE                                                                                            
                    109:        { "TCP_KEEPIDLE",               SOCK_STREAM,    IPPROTO_TCP,    TCP_KEEPIDLE            },
                    110: #endif                                                                                                                 
                    111: #ifdef TCP_KEEPINTVL                                                                                   
                    112:        { "TCP_KEEPINTVL",              SOCK_STREAM,    IPPROTO_TCP,    TCP_KEEPINTVL           },
                    113: #endif                                                                                                                 
                    114: #ifdef TCP_KEEPCNT                                                                                             
                    115:        { "TCP_KEEPCNT",                SOCK_STREAM,    IPPROTO_TCP,    TCP_KEEPCNT                     },
                    116: #endif                                                                                                                 
                    117: #ifdef TCP_KEEPALIVE   /* SunOS */
                    118:        { "TCP_KEEPALIVE",              SOCK_STREAM,    IPPROTO_TCP,    TCP_KEEPALIVE           },
                    119: #endif                                                                                                                 
                    120: #ifdef TCP_SYNCNT                                                                                              
                    121:        { "TCP_SYNCNT",                 SOCK_STREAM,    IPPROTO_TCP,    TCP_SYNCNT                      },
                    122: #endif                                                                                                                 
                    123: #ifdef TCP_LINGER2                                                                                             
                    124:        { "TCP_LINGER2",                SOCK_STREAM,    IPPROTO_TCP,    TCP_LINGER2                     },
                    125: #endif                                                                                                         
                    126: #ifdef TCP_DEFER_ACCEPT                                                                                
                    127:        { "TCP_DEFER_ACCEPT",   SOCK_STREAM,    IPPROTO_TCP,    TCP_DEFER_ACCEPT        },
                    128: #endif                                                                                                                 
                    129: #ifdef TCP_WINDOW_CLAMP                                                                                        
                    130:        { "TCP_WINDOW_CLAMP",   SOCK_STREAM,    IPPROTO_TCP,    TCP_WINDOW_CLAMP        },
                    131: #endif                                                                                                         
                    132: #ifdef TCP_QUICKACK                                                                                    
                    133:        { "TCP_QUICKACK",               SOCK_STREAM,    IPPROTO_TCP,    TCP_QUICKACK            },
                    134: #endif                                         
                    135: #ifdef TCP_NOPUSH                      
                    136:        { "TCP_NOPUSH",                 SOCK_STREAM,    IPPROTO_TCP,    TCP_NOPUSH                      },
                    137: #endif                                         
                    138: #ifdef TCP_NOOPT                       
                    139:        { "TCP_NOOPT",                  SOCK_STREAM,    IPPROTO_TCP,    TCP_NOOPT                       },
                    140: #endif
                    141:        { NULL }
                    142: };
                    143: 
                    144: int getSocketOptionByName(const char* name, int* level)
                    145: {
                    146:        int i;
                    147: 
                    148:        if(level!=NULL)
                    149:                *level=SOL_SOCKET;      /* default option level */
                    150:        for(i=0;socket_options[i].name;i++) {
                    151:                if(stricmp(name,socket_options[i].name)==0) {
                    152:                        if(level!=NULL)
                    153:                                *level = socket_options[i].level;
                    154:                        return(socket_options[i].value);
                    155:                }
                    156:        }
                    157:        if(!isdigit(*name))     /* unknown option name */
                    158:                return(-1);
                    159:        return(strtol(name,NULL,0));
                    160: }
                    161: 
                    162: socket_option_t* getSocketOptionList(void)
                    163: {
                    164:        return(socket_options);
                    165: }
                    166: 
1.1.1.2 ! root      167: int sendfilesocket(int sock, int file, off_t *offset, off_t count)
1.1       root      168: {
1.1.1.2 ! root      169:        char            buf[1024*16];
        !           170:        off_t           len;
        !           171:        int                     rd;
        !           172:        int                     wr=0;
        !           173:        int                     total=0;
        !           174:        int                     i;
1.1       root      175: 
                    176: /* sendfile() on Linux may or may not work with non-blocking sockets ToDo */
                    177:        len=filelength(file);
                    178: 
                    179:        if(offset!=NULL)
                    180:                if(lseek(file,*offset,SEEK_SET)<0)
                    181:                        return(-1);
                    182: 
                    183:        if(count<1 || count>len) {
                    184:                count=len;
                    185:                count-=tell(file);              /* don't try to read beyond EOF */
                    186:        }
                    187: #if USE_SENDFILE
                    188:        while((i=sendfile(file,sock,(offset==NULL?0:*offset)+total,count-total,NULL,&wr,0))==-1 && errno==EAGAIN)  {
                    189:                total+=wr;
                    190:                SLEEP(1);
                    191:        }
                    192:        if(i==0)
                    193:                return((int)count);
                    194: #endif
                    195: 
                    196:        if(count<0) {
                    197:                errno=EINVAL;
                    198:                return(-1);
                    199:        }
                    200: 
                    201:        while(total<count) {
                    202:                rd=read(file,buf,sizeof(buf));
                    203:                if(rd==-1)
                    204:                        return(-1);
                    205:                if(rd==0)
                    206:                        break;
                    207:                for(i=wr=0;i<rd;i+=wr) {
                    208:                        wr=sendsocket(sock,buf+i,rd-i);
                    209:                        if(wr>0)
                    210:                                continue;
                    211:                        if(wr==SOCKET_ERROR && ERROR_VALUE==EWOULDBLOCK) {
                    212:                                wr=0;
                    213:                                SLEEP(1);
                    214:                                continue;
                    215:                        }
                    216:                        return(wr);
                    217:                }
                    218:                if(i!=rd)
                    219:                        return(-1);
                    220:                total+=rd;
                    221:        }
                    222: 
                    223:        if(offset!=NULL)
                    224:                (*offset)+=total;
                    225: 
                    226:        return(total);
                    227: }
                    228: 
1.1.1.2 ! root      229: int recvfilesocket(int sock, int file, off_t *offset, off_t count)
1.1       root      230: {
                    231:        /* Writes a file from a socket -
                    232:         *
                    233:         * sock         - Socket to read from
                    234:         * file         - File descriptior to write to
                    235:         *                              MUST be open and writeable
                    236:         * offset       - pointer to file offset to start writing at
                    237:         *                              is set to offset writing STOPPED
                    238:         *                              on return
                    239:         * count        - number of bytes to read/write
                    240:         *
                    241:         * returns -1 if an error occurse, otherwise
                    242:         * returns number ob bytes written and sets offset
                    243:         * to the new offset
                    244:         */
                    245:         
                    246:        char*   buf;
                    247:        int             rd;
                    248:        int             wr;
                    249: 
                    250:        if(count<1) {
                    251:                errno=ERANGE;
                    252:                return(-1);
                    253:        }
                    254:                
1.1.1.2 ! root      255:        if((buf=(char*)alloca((size_t)count))==NULL) {
1.1       root      256:                errno=ENOMEM;
                    257:                return(-1);
                    258:        }
                    259: 
                    260:        if(offset!=NULL)
                    261:                if(lseek(file,*offset,SEEK_SET)<0)
                    262:                        return(-1);
                    263: 
1.1.1.2 ! root      264:        rd=read(sock,buf,(size_t)count);
1.1       root      265:        if(rd!=count)
                    266:                return(-1);
                    267: 
                    268:        wr=write(file,buf,rd);
                    269: 
                    270:        if(offset!=NULL)
                    271:                (*offset)+=wr;
                    272: 
                    273:        return(wr);
                    274: }
                    275: 
                    276: 
                    277: /* Return true if connected, optionally sets *rd_p to true if read data available */
                    278: BOOL socket_check(SOCKET sock, BOOL* rd_p, BOOL* wr_p, DWORD timeout)
                    279: {
                    280:        char    ch;
                    281:        int             i,rd;
                    282:        fd_set  rd_set;
                    283:        fd_set* rd_set_p=&rd_set;
                    284:        fd_set  wr_set;
                    285:        fd_set* wr_set_p=NULL;
                    286:        struct  timeval tv;
                    287: 
                    288:        if(rd_p!=NULL)
                    289:                *rd_p=FALSE;
                    290: 
                    291:        if(wr_p!=NULL)
                    292:                *wr_p=FALSE;
                    293: 
                    294:        if(sock==INVALID_SOCKET)
                    295:                return(FALSE);
                    296: 
                    297:        FD_ZERO(&rd_set);
                    298:        FD_SET(sock,&rd_set);
                    299:        if(wr_p!=NULL) {
                    300:                wr_set_p=&wr_set;
                    301:                FD_ZERO(wr_set_p);
                    302:                FD_SET(sock,wr_set_p);
                    303:                if(rd_p==NULL)
                    304:                        rd_set_p=NULL;
                    305:        }
                    306: 
                    307:        /* Convert timeout from ms to sec/usec */
                    308:        tv.tv_sec=timeout/1000;
                    309:        tv.tv_usec=(timeout%1000)*1000;
                    310: 
                    311:        i=select(sock+1,rd_set_p,wr_set_p,NULL,&tv);
                    312:        if(i==SOCKET_ERROR)
                    313:                return(FALSE);
                    314: 
                    315:        if(i==0) 
                    316:                return(TRUE);
                    317: 
                    318:        if(wr_p!=NULL && FD_ISSET(sock,wr_set_p)) {
                    319:                *wr_p=TRUE;
                    320:                if(i==1)
                    321:                        return(TRUE);
                    322:        }
                    323: 
                    324:        if(rd_p !=NULL || wr_p==NULL)  {
                    325:                rd=recv(sock,&ch,1,MSG_PEEK);
                    326:                if(rd==1 
                    327:                        || (rd==SOCKET_ERROR && ERROR_VALUE==EMSGSIZE)) {
                    328:                        if(rd_p!=NULL)
                    329:                                *rd_p=TRUE;
                    330:                        return(TRUE);
                    331:                }
                    332:        }
                    333: 
                    334:        return(FALSE);
                    335: }
                    336: 
                    337: int retry_bind(SOCKET s, const struct sockaddr *addr, socklen_t addrlen
                    338:                           ,uint retries, uint wait_secs
                    339:                           ,const char* prot
1.1.1.2 ! root      340:                           ,int (*lprintf)(int level, const char *fmt, ...))
1.1       root      341: {
                    342:        char    port_str[128];
                    343:        int             result=-1;
                    344:        uint    i;
                    345: 
                    346:        if(addr->sa_family==AF_INET)
                    347:                SAFEPRINTF(port_str," to port %u",ntohs(((SOCKADDR_IN *)(addr))->sin_port)); 
                    348:        else
                    349:                port_str[0]=0;
                    350:        for(i=0;i<=retries;i++) {
                    351:                if((result=bind(s,addr,addrlen))==0)
                    352:                        break;
                    353:                if(lprintf!=NULL)
1.1.1.2 ! root      354:                        lprintf(i<retries ? LOG_WARNING:LOG_CRIT
1.1       root      355:                                ,"%04d !ERROR %d binding %s socket%s", s, ERROR_VALUE, prot, port_str);
                    356:                if(i<retries) {
                    357:                        if(lprintf!=NULL)
                    358:                                lprintf(LOG_WARNING,"%04d Will retry in %u seconds (%u of %u)"
                    359:                                        ,s, wait_secs, i+1, retries);
                    360:                        SLEEP(wait_secs*1000);
                    361:                }
                    362:        }
                    363:        return(result);
                    364: }
1.1.1.2 ! root      365: 
        !           366: int nonblocking_connect(SOCKET sock, struct sockaddr* addr, size_t size, unsigned timeout)
        !           367: {
        !           368:        int result;
        !           369: 
        !           370:        result=connect(sock, addr, size);
        !           371: 
        !           372:        if(result==SOCKET_ERROR
        !           373:                && (ERROR_VALUE==EWOULDBLOCK || ERROR_VALUE==EINPROGRESS)) {
        !           374:                fd_set          socket_set;
        !           375:                struct          timeval tv;
        !           376:                socklen_t       optlen=sizeof(result);
        !           377:                tv.tv_sec = timeout;
        !           378:                tv.tv_usec = 0;
        !           379:                FD_ZERO(&socket_set);
        !           380:                FD_SET(sock,&socket_set);
        !           381:                if(select(sock+1,NULL,&socket_set,NULL,&tv)==1)
        !           382:                        getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&result, &optlen);
        !           383:        }
        !           384:        return result;
        !           385: }

unix.superglobalmegacorp.com

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