|
|
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.