|
1
|
/* |
|
2
|
** Copyright (c) 2009 D. Richard Hipp |
|
3
|
** |
|
4
|
** This program is free software; you can redistribute it and/or |
|
5
|
** modify it under the terms of the Simplified BSD License (also |
|
6
|
** known as the "2-Clause License" or "FreeBSD License".) |
|
7
|
|
|
8
|
** This program is distributed in the hope that it will be useful, |
|
9
|
** but without any warranty; without even the implied warranty of |
|
10
|
** merchantability or fitness for a particular purpose. |
|
11
|
** |
|
12
|
** Author contact information: |
|
13
|
** [email protected] |
|
14
|
** http://www.hwaci.com/drh/ |
|
15
|
** |
|
16
|
******************************************************************************* |
|
17
|
** |
|
18
|
** This file manages low-level client socket communications. The socket |
|
19
|
** might be for a simple HTTP request or for an encrypted HTTPS request. |
|
20
|
** |
|
21
|
** This file implements a singleton. A single client socket may be active |
|
22
|
** at a time. State information is stored in static variables. The identity |
|
23
|
** of the server is held in global variables that are set by url_parse(). |
|
24
|
** |
|
25
|
** Low-level sockets are abstracted out into this module because they |
|
26
|
** are handled different on Unix and windows. |
|
27
|
*/ |
|
28
|
#if defined(_WIN32) |
|
29
|
# if defined(_WIN32_WINNT) |
|
30
|
# undef _WIN32_WINNT |
|
31
|
# endif |
|
32
|
# define _WIN32_WINNT 0x501 |
|
33
|
#endif |
|
34
|
#ifndef __EXTENSIONS__ |
|
35
|
# define __EXTENSIONS__ 1 /* IPv6 won't compile on Solaris without this */ |
|
36
|
#endif |
|
37
|
#include "config.h" |
|
38
|
#include "http_socket.h" |
|
39
|
#if defined(_WIN32) |
|
40
|
# include <winsock2.h> |
|
41
|
# include <ws2tcpip.h> |
|
42
|
#else |
|
43
|
# include <netinet/in.h> |
|
44
|
# include <arpa/inet.h> |
|
45
|
# include <sys/socket.h> |
|
46
|
# include <netdb.h> |
|
47
|
#endif |
|
48
|
#include <assert.h> |
|
49
|
#include <sys/types.h> |
|
50
|
#include <signal.h> |
|
51
|
|
|
52
|
/* |
|
53
|
** There can only be a single socket connection open at a time. |
|
54
|
** State information about that socket is stored in the following |
|
55
|
** local variables: |
|
56
|
*/ |
|
57
|
static int socketIsInit = 0; /* True after global initialization */ |
|
58
|
#if defined(_WIN32) |
|
59
|
static WSADATA socketInfo; /* Windows socket initialize data */ |
|
60
|
#endif |
|
61
|
static int iSocket = -1; /* The socket on which we talk to the server */ |
|
62
|
static char *socketErrMsg = 0; /* Text of most recent socket error */ |
|
63
|
|
|
64
|
|
|
65
|
/* |
|
66
|
** Clear the socket error message |
|
67
|
*/ |
|
68
|
static void socket_clear_errmsg(void){ |
|
69
|
free(socketErrMsg); |
|
70
|
socketErrMsg = 0; |
|
71
|
} |
|
72
|
|
|
73
|
/* |
|
74
|
** Set the socket error message. |
|
75
|
*/ |
|
76
|
void socket_set_errmsg(const char *zFormat, ...){ |
|
77
|
va_list ap; |
|
78
|
socket_clear_errmsg(); |
|
79
|
va_start(ap, zFormat); |
|
80
|
socketErrMsg = vmprintf(zFormat, ap); |
|
81
|
va_end(ap); |
|
82
|
} |
|
83
|
|
|
84
|
/* |
|
85
|
** Return the current socket error message |
|
86
|
*/ |
|
87
|
char *socket_errmsg(void){ |
|
88
|
char *zResult = socketErrMsg; |
|
89
|
socketErrMsg = 0; |
|
90
|
return zResult; |
|
91
|
} |
|
92
|
|
|
93
|
/* |
|
94
|
** Return the file descriptor for the open socket. |
|
95
|
*/ |
|
96
|
int socket_get_fd(){ |
|
97
|
return iSocket; |
|
98
|
} |
|
99
|
|
|
100
|
/* |
|
101
|
** Call this routine once before any other use of the socket interface. |
|
102
|
** This routine does initial configuration of the socket module. |
|
103
|
*/ |
|
104
|
void socket_global_init(void){ |
|
105
|
if( socketIsInit==0 ){ |
|
106
|
#if defined(_WIN32) |
|
107
|
if( WSAStartup(MAKEWORD(2,0), &socketInfo)!=0 ){ |
|
108
|
fossil_panic("can't initialize winsock"); |
|
109
|
} |
|
110
|
#endif |
|
111
|
socketIsInit = 1; |
|
112
|
} |
|
113
|
} |
|
114
|
|
|
115
|
/* |
|
116
|
** Call this routine to shutdown the socket module prior to program |
|
117
|
** exit. |
|
118
|
*/ |
|
119
|
void socket_global_shutdown(void){ |
|
120
|
if( socketIsInit ){ |
|
121
|
#if defined(_WIN32) |
|
122
|
WSACleanup(); |
|
123
|
#endif |
|
124
|
socket_clear_errmsg(); |
|
125
|
socketIsInit = 0; |
|
126
|
} |
|
127
|
} |
|
128
|
|
|
129
|
/* |
|
130
|
** Close the currently open socket. If no socket is open, this routine |
|
131
|
** is a no-op. |
|
132
|
*/ |
|
133
|
void socket_close(void){ |
|
134
|
if( iSocket>=0 ){ |
|
135
|
#if defined(_WIN32) |
|
136
|
if( shutdown(iSocket,1)==0 ) shutdown(iSocket,0); |
|
137
|
closesocket(iSocket); |
|
138
|
#else |
|
139
|
close(iSocket); |
|
140
|
#endif |
|
141
|
iSocket = -1; |
|
142
|
} |
|
143
|
} |
|
144
|
|
|
145
|
/* |
|
146
|
** Open a socket connection. The identify of the server is determined |
|
147
|
** by pUrlData |
|
148
|
** |
|
149
|
** pUrlData->name Name of the server. Ex: fossil-scm.org |
|
150
|
** pUrlData->port TCP/IP port to use. Ex: 80 |
|
151
|
** |
|
152
|
** Return the number of errors. |
|
153
|
*/ |
|
154
|
int socket_open(UrlData *pUrlData){ |
|
155
|
int rc = 0; |
|
156
|
struct addrinfo *ai = 0; |
|
157
|
struct addrinfo *p; |
|
158
|
struct addrinfo hints; |
|
159
|
char zPort[30]; |
|
160
|
char zRemote[NI_MAXHOST]; |
|
161
|
|
|
162
|
socket_global_init(); |
|
163
|
socket_close(); |
|
164
|
memset(&hints, 0, sizeof(struct addrinfo)); |
|
165
|
switch( g.eIPvers ){ |
|
166
|
default: hints.ai_family = AF_UNSPEC; break; |
|
167
|
case 1: hints.ai_family = AF_INET; break; |
|
168
|
case 2: hints.ai_family = AF_INET6; break; |
|
169
|
} |
|
170
|
hints.ai_socktype = SOCK_STREAM; |
|
171
|
hints.ai_protocol = IPPROTO_TCP; |
|
172
|
sqlite3_snprintf(sizeof(zPort),zPort,"%d", pUrlData->port); |
|
173
|
rc = getaddrinfo(pUrlData->name, zPort, &hints, &ai); |
|
174
|
if( rc ){ |
|
175
|
socket_set_errmsg("getaddrinfo() fails: %s", gai_strerror(rc)); |
|
176
|
goto end_socket_open; |
|
177
|
} |
|
178
|
for(p=ai; p; p=p->ai_next){ |
|
179
|
iSocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol); |
|
180
|
if( iSocket<0 ) continue; |
|
181
|
if( connect(iSocket,p->ai_addr,p->ai_addrlen)<0 ){ |
|
182
|
socket_close(); |
|
183
|
continue; |
|
184
|
} |
|
185
|
rc = getnameinfo(p->ai_addr, p->ai_addrlen, zRemote, sizeof(zRemote), |
|
186
|
0, 0, NI_NUMERICHOST); |
|
187
|
if( rc ){ |
|
188
|
socket_set_errmsg("getnameinfo() failed: %s", gai_strerror(rc)); |
|
189
|
goto end_socket_open; |
|
190
|
} |
|
191
|
g.zIpAddr = fossil_strdup(zRemote); |
|
192
|
break; |
|
193
|
} |
|
194
|
if( p==0 ){ |
|
195
|
socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name, |
|
196
|
pUrlData->port); |
|
197
|
rc = 1; |
|
198
|
} |
|
199
|
#if !defined(_WIN32) |
|
200
|
signal(SIGPIPE, SIG_IGN); |
|
201
|
#endif |
|
202
|
end_socket_open: |
|
203
|
if( rc && iSocket>=0 ) socket_close(); |
|
204
|
if( ai ) freeaddrinfo(ai); |
|
205
|
return rc; |
|
206
|
} |
|
207
|
|
|
208
|
/* |
|
209
|
** Send content out over the open socket connection. |
|
210
|
*/ |
|
211
|
size_t socket_send(void *NotUsed, const void *pContent, size_t N){ |
|
212
|
ssize_t sent; |
|
213
|
size_t total = 0; |
|
214
|
while( N>0 ){ |
|
215
|
sent = send(iSocket, pContent, N, 0); |
|
216
|
if( sent<=0 ) break; |
|
217
|
total += (size_t)sent; |
|
218
|
N -= (size_t)sent; |
|
219
|
pContent = (void*)&((char*)pContent)[sent]; |
|
220
|
} |
|
221
|
return total; |
|
222
|
} |
|
223
|
|
|
224
|
/* |
|
225
|
** Receive content back from the open socket connection. |
|
226
|
** Return the number of bytes read. |
|
227
|
** |
|
228
|
** When bDontBlock is false, this function blocks until all N bytes |
|
229
|
** have been read. |
|
230
|
*/ |
|
231
|
size_t socket_receive(void *NotUsed, void *pContent, size_t N, int bDontBlock){ |
|
232
|
ssize_t got; |
|
233
|
size_t total = 0; |
|
234
|
int flags = 0; |
|
235
|
#ifdef MSG_DONTWAIT |
|
236
|
if( bDontBlock ) flags |= MSG_DONTWAIT; |
|
237
|
#endif |
|
238
|
while( N>0 ){ |
|
239
|
/* WinXP fails for large values of N. So limit it to 64KiB. */ |
|
240
|
got = recv(iSocket, pContent, N>65536 ? 65536 : N, flags); |
|
241
|
if( got<=0 ) break; |
|
242
|
total += (size_t)got; |
|
243
|
N -= (size_t)got; |
|
244
|
pContent = (void*)&((char*)pContent)[got]; |
|
245
|
} |
|
246
|
return total; |
|
247
|
} |
|
248
|
|