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