|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.