sockwrap.c 5.85 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* sockwrap.c */

/* Berkley/WinSock socket API wrappers */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html		*
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 *																			*
 * This library is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU Lesser General Public License		*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU Lesser General Public License for more details: lgpl.txt or	*
 * http://www.fsf.org/copyleft/lesser.html									*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

38
#include <stdlib.h>		/* malloc/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

44
#include "genwrap.h"	/* SLEEP */
deuce's avatar
deuce committed
45
#include "gen_defs.h"	/* BOOL/LOG_WARNING */
46
47
48
49
50
#include "sockwrap.h"	/* sendsocket */
#include "filewrap.h"	/* filelength */

int sendfilesocket(int sock, int file, long *offset, long count)
{
51
	char	buf[1024*16];
52
53
	long	len;
	int		rd;
54
55
	int		wr=0;
	int		total=0;
56
	int		i;
57

58
59
60
/* sendfile() on Linux may or may not work with non-blocking sockets ToDo */
	len=filelength(file);

61
62
63
64
	if(offset!=NULL)
		if(lseek(file,*offset,SEEK_SET)<0)
			return(-1);

65
	if(count<1 || count>len) {
66
		count=len;
67
68
		count-=tell(file);		/* don't try to read beyond EOF */
	}
69
70
71
72
73
74
75
76
#if USE_SENDFILE
	while((i=sendfile(file,sock,(offset==NULL?0:*offset)+total,count-total,NULL,&wr,0))==-1 && errno==EAGAIN)  {
		total+=wr;
		SLEEP(1);
	}
	if(i==0)
		return((int)count);
#endif
77

78
79
80
81
82
83
	if(count<0) {
		errno=EINVAL;
		return(-1);
	}

	while(total<count) {
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
		rd=read(file,buf,sizeof(buf));
		if(rd==-1)
			return(-1);
		if(rd==0)
			break;
		for(i=wr=0;i<rd;i+=wr) {
			wr=sendsocket(sock,buf+i,rd-i);
			if(wr>0)
				continue;
			if(wr==SOCKET_ERROR && ERROR_VALUE==EWOULDBLOCK) {
				wr=0;
				SLEEP(1);
				continue;
			}
			return(wr);
99
		}
100
101
102
		if(i!=rd)
			return(-1);
		total+=rd;
103
104
	}

105
	if(offset!=NULL)
106
107
108
		(*offset)+=total;

	return(total);
109
110
}

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
int recvfilesocket(int sock, int file, long *offset, long count)
{
	/* Writes a file from a socket -
	 *
	 * sock		- Socket to read from
	 * file		- File descriptior to write to
	 *				MUST be open and writeable
	 * offset	- pointer to file offset to start writing at
	 *				is set to offset writing STOPPED
	 *				on return
	 * count	- number of bytes to read/write
	 *
	 * returns -1 if an error occurse, otherwise
	 * returns number ob bytes written and sets offset
	 * to the new offset
	 */
	 
	char*	buf;
	int		rd;
	int		wr;

	if(count<1) {
		errno=ERANGE;
		return(-1);
	}
		
137
	if((buf=(char*)malloc(count))==NULL) {
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
		errno=ENOMEM;
		return(-1);
	}

	if(offset!=NULL)
		if(lseek(file,*offset,SEEK_SET)<0)
			return(-1);

	rd=read(sock,buf,count);
	if(rd!=count) {
		free(buf);
		return(-1);
	}

	wr=write(file,buf,rd);
	free(buf);

	if(offset!=NULL)
		(*offset)+=wr;

	return(wr);
}


162
/* Return true if connected, optionally sets *rd_p to true if read data available */
163
BOOL socket_check(SOCKET sock, BOOL* rd_p, BOOL* wr_p, DWORD timeout)
164
165
166
{
	char	ch;
	int		i,rd;
167
	fd_set	rd_set;
168
	fd_set*	rd_set_p=&rd_set;
169
170
	fd_set	wr_set;
	fd_set*	wr_set_p=NULL;
171
172
173
174
175
	struct	timeval tv;

	if(rd_p!=NULL)
		*rd_p=FALSE;

176
177
178
	if(wr_p!=NULL)
		*wr_p=FALSE;

179
180
181
	if(sock==INVALID_SOCKET)
		return(FALSE);

182
183
184
185
186
187
	FD_ZERO(&rd_set);
	FD_SET(sock,&rd_set);
	if(wr_p!=NULL) {
		wr_set_p=&wr_set;
		FD_ZERO(wr_set_p);
		FD_SET(sock,wr_set_p);
188
		if(rd_p==NULL)
189
			rd_set_p=NULL;
190
	}
191

192
193
194
	/* Convert timeout from ms to sec/usec */
	tv.tv_sec=timeout/1000;
	tv.tv_usec=(timeout%1000)*1000;
195

196
	i=select(sock+1,rd_set_p,wr_set_p,NULL,&tv);
197
198
199
200
201
202
	if(i==SOCKET_ERROR)
		return(FALSE);

	if(i==0) 
		return(TRUE);

203
204
205
206
207
208
	if(wr_p!=NULL && FD_ISSET(sock,wr_set_p)) {
		*wr_p=TRUE;
		if(i==1)
			return(TRUE);
	}

209
	if(rd_p !=NULL || wr_p==NULL)  {
210
211
212
213
214
215
216
		rd=recv(sock,&ch,1,MSG_PEEK);
		if(rd==1 
			|| (rd==SOCKET_ERROR && ERROR_VALUE==EMSGSIZE)) {
			if(rd_p!=NULL)
				*rd_p=TRUE;
			return(TRUE);
		}
217
218
219
220
	}

	return(FALSE);
}
deuce's avatar
deuce committed
221

222
223
224
225
int retry_bind(SOCKET s, const struct sockaddr *addr, socklen_t addrlen
			   ,uint retries, uint wait_secs
			   ,const char* prot
			   ,int (*lprintf)(int level, char *fmt, ...))
deuce's avatar
deuce committed
226
{
227
	char	port_str[128];
deuce's avatar
deuce committed
228
	int		result=-1;
229
	uint	i;
deuce's avatar
deuce committed
230

231
	if(addr->sa_family==AF_INET)
232
		SAFEPRINTF(port_str," to port %u",ntohs(((SOCKADDR_IN *)(addr))->sin_port)); 
233
234
	else
		port_str[0]=0;
deuce's avatar
deuce committed
235
	for(i=0;i<=retries;i++) {
236
		if((result=bind(s,addr,addrlen))==0)
deuce's avatar
deuce committed
237
			break;
238
239
240
241
242
		if(lprintf!=NULL)
			lprintf(i<retries ? LOG_WARNING:LOG_ERR
				,"%04d !ERROR %d binding %s socket%s", s, ERROR_VALUE, prot, port_str);
		if(i<retries) {
			if(lprintf!=NULL)
243
244
				lprintf(LOG_WARNING,"%04d Will retry in %u seconds (%u of %u)"
					,s, wait_secs, i+1, retries);
245
246
			SLEEP(wait_secs*1000);
		}
deuce's avatar
deuce committed
247
248
249
	}
	return(result);
}