Fossil SCM

fossil-scm / src / http_socket.c
Blame History Raw 248 lines
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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button