Fossil SCM

The "fossil server" command on windows now listens for both IPv4 and IPv6 connections.

drh 2018-01-01 18:56 trunk merge
Commit 21d5038fd097cc572c30e184dd9b79445f7284443f728edf488e56093f7a3a58
1 file changed +48 -16
+48 -16
--- src/winhttp.c
+++ src/winhttp.c
@@ -20,13 +20,18 @@
2020
** server to be run without any user logged on.
2121
*/
2222
#include "config.h"
2323
#ifdef _WIN32
2424
/* This code is for win32 only */
25
+#include <ws2tcpip.h>
2526
#include <windows.h>
2627
#include <process.h>
2728
#include "winhttp.h"
29
+
30
+#ifndef IPV6_V6ONLY
31
+# define IPV6_V6ONLY 27 /* Because this definition is missing in MinGW */
32
+#endif
2833
2934
/*
3035
** The HttpServer structure holds information about an instance of
3136
** the HTTP server itself.
3237
*/
@@ -46,11 +51,11 @@
4651
*/
4752
typedef struct HttpRequest HttpRequest;
4853
struct HttpRequest {
4954
int id; /* ID counter */
5055
SOCKET s; /* Socket on which to receive data */
51
- SOCKADDR_IN addr; /* Address from which data is coming */
56
+ SOCKADDR_IN6 addr; /* Address from which data is coming */
5257
int flags; /* Flags passed to win32_http_server() */
5358
const char *zOptions; /* --baseurl, --notfound, --localauth, --th-trace */
5459
};
5560
5661
/*
@@ -135,10 +140,12 @@
135140
HttpRequest *p = (HttpRequest*)pAppData;
136141
FILE *in = 0, *out = 0, *aux = 0;
137142
int amt, got, i;
138143
int wanted = 0;
139144
char *z;
145
+ char zIp[50];
146
+ DWORD nIp = sizeof(zIp);
140147
char zCmdFName[MAX_PATH];
141148
char zRequestFName[MAX_PATH];
142149
char zReplyFName[MAX_PATH];
143150
char zCmd[2000]; /* Command-line to process the request */
144151
char zHdr[4000]; /* The HTTP request header */
@@ -183,19 +190,22 @@
183190
/*
184191
** The repository name is only needed if there was no open checkout. This
185192
** is designed to allow the open checkout for the interactive user to work
186193
** with the local Fossil server started via the "ui" command.
187194
*/
195
+ if( WSAAddressToStringA((SOCKADDR*)&p->addr, sizeof(p->addr),
196
+ NULL, zIp, &nIp)!=0 ){
197
+ zIp[0] = 0;
198
+ }
188199
if( (p->flags & HTTP_SERVER_HAD_CHECKOUT)==0 ){
189200
assert( g.zRepositoryName && g.zRepositoryName[0] );
190201
sqlite3_snprintf(sizeof(zCmd), zCmd, "%s%s\n%s\n%s\n%s",
191
- get_utf8_bom(0), zRequestFName, zReplyFName, inet_ntoa(p->addr.sin_addr),
192
- g.zRepositoryName
202
+ get_utf8_bom(0), zRequestFName, zReplyFName, zIp, g.zRepositoryName
193203
);
194204
}else{
195205
sqlite3_snprintf(sizeof(zCmd), zCmd, "%s%s\n%s\n%s",
196
- get_utf8_bom(0), zRequestFName, zReplyFName, inet_ntoa(p->addr.sin_addr)
206
+ get_utf8_bom(0), zRequestFName, zReplyFName, zIp
197207
);
198208
}
199209
aux = fossil_fopen(zCmdFName, "wb");
200210
if( aux==0 ) goto end_request;
201211
fwrite(zCmd, 1, strlen(zCmd), aux);
@@ -235,10 +245,12 @@
235245
static void win32_scgi_request(void *pAppData){
236246
HttpRequest *p = (HttpRequest*)pAppData;
237247
FILE *in = 0, *out = 0;
238248
int amt, got, nHdr, i;
239249
int wanted = 0;
250
+ char zIp[50];
251
+ DWORD nIp = sizeof(zIp);
240252
char zRequestFName[MAX_PATH];
241253
char zReplyFName[MAX_PATH];
242254
char zCmd[2000]; /* Command-line to process the request */
243255
char zHdr[4000]; /* The SCGI request header */
244256
@@ -265,13 +277,17 @@
265277
if( got<=0 ) break;
266278
fwrite(zHdr, 1, got, out);
267279
wanted += got;
268280
}
269281
assert( g.zRepositoryName && g.zRepositoryName[0] );
282
+ if (WSAAddressToStringA((SOCKADDR*)&p->addr, sizeof(p->addr),
283
+ NULL, zIp, &nIp)!=0){
284
+ zIp[0] = 0;
285
+ }
270286
sqlite3_snprintf(sizeof(zCmd), zCmd,
271287
"\"%s\" http \"%s\" \"%s\" %s \"%s\" --scgi --nossl%s",
272
- g.nameOfExe, zRequestFName, zReplyFName, inet_ntoa(p->addr.sin_addr),
288
+ g.nameOfExe, zRequestFName, zReplyFName, zIp,
273289
g.zRepositoryName, p->zOptions
274290
);
275291
in = fossil_fopen(zReplyFName, "w+b");
276292
fflush(out);
277293
fossil_system(zCmd);
@@ -311,11 +327,12 @@
311327
int flags /* One or more HTTP_SERVER_ flags */
312328
){
313329
HANDLE hStoppedEvent;
314330
WSADATA wd;
315331
SOCKET s = INVALID_SOCKET;
316
- SOCKADDR_IN addr;
332
+ SOCKADDR_IN6 addr;
333
+ int addrlen;
317334
int idCnt = 0;
318335
int iPort = mnPort;
319336
Blob options;
320337
wchar_t zTmpPath[MAX_PATH];
321338
const char *zSkin;
@@ -353,29 +370,44 @@
353370
if( zSavedKey!=0 && savedKeySize>0 ){
354371
blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(),
355372
zSavedKey, savedKeySize);
356373
}
357374
#endif
358
- if( WSAStartup(MAKEWORD(1,1), &wd) ){
375
+ if( WSAStartup(MAKEWORD(2,0), &wd) ){
359376
fossil_fatal("unable to initialize winsock");
360377
}
378
+ if( flags & HTTP_SERVER_LOCALHOST ){
379
+ zIpAddr = "127.0.0.1";
380
+ }
361381
while( iPort<=mxPort ){
362
- s = socket(AF_INET, SOCK_STREAM, 0);
382
+ DWORD ipv6only = 0;
383
+ s = socket(AF_INET6, SOCK_STREAM, 0);
363384
if( s==INVALID_SOCKET ){
364385
fossil_fatal("unable to create a socket");
365386
}
366
- addr.sin_family = AF_INET;
367
- addr.sin_port = htons(iPort);
387
+ setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only,
388
+ sizeof(ipv6only));
389
+ memset(&addr, 0, sizeof(addr));
390
+ addrlen = sizeof(addr);
368391
if( zIpAddr ){
369
- addr.sin_addr.s_addr = inet_addr(zIpAddr);
370
- if( addr.sin_addr.s_addr == (-1) ){
392
+ char* zIp;
393
+ if( strstr(zIpAddr, ".") ){
394
+ zIp = mprintf("::ffff:%s", zIpAddr);
395
+ }else{
396
+ zIp = mprintf("%s", zIpAddr);
397
+ }
398
+ addr.sin6_family = AF_INET6;
399
+ if (WSAStringToAddress(zIp, AF_INET6, NULL,
400
+ (struct sockaddr *)&addr, &addrlen) != 0){
371401
fossil_fatal("not a valid IP address: %s", zIpAddr);
372402
}
373
- }else if( flags & HTTP_SERVER_LOCALHOST ){
374
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
403
+ ((SOCKADDR_IN6*)&addr)->sin6_port = htons(iPort);
404
+ fossil_free(zIp);
375405
}else{
376
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
406
+ addr.sin6_family = AF_INET6;
407
+ addr.sin6_port = htons(iPort);
408
+ memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
377409
}
378410
if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){
379411
closesocket(s);
380412
iPort++;
381413
continue;
@@ -430,11 +462,11 @@
430462
/* Set the service status to running and pass the listener socket to the
431463
** service handling procedures. */
432464
win32_http_service_running(s);
433465
for(;;){
434466
SOCKET client;
435
- SOCKADDR_IN client_addr;
467
+ SOCKADDR_IN6 client_addr;
436468
HttpRequest *pRequest;
437469
int len = sizeof(client_addr);
438470
int wsaError;
439471
440472
client = accept(s, (struct sockaddr*)&client_addr, &len);
441473
--- src/winhttp.c
+++ src/winhttp.c
@@ -20,13 +20,18 @@
20 ** server to be run without any user logged on.
21 */
22 #include "config.h"
23 #ifdef _WIN32
24 /* This code is for win32 only */
 
25 #include <windows.h>
26 #include <process.h>
27 #include "winhttp.h"
 
 
 
 
28
29 /*
30 ** The HttpServer structure holds information about an instance of
31 ** the HTTP server itself.
32 */
@@ -46,11 +51,11 @@
46 */
47 typedef struct HttpRequest HttpRequest;
48 struct HttpRequest {
49 int id; /* ID counter */
50 SOCKET s; /* Socket on which to receive data */
51 SOCKADDR_IN addr; /* Address from which data is coming */
52 int flags; /* Flags passed to win32_http_server() */
53 const char *zOptions; /* --baseurl, --notfound, --localauth, --th-trace */
54 };
55
56 /*
@@ -135,10 +140,12 @@
135 HttpRequest *p = (HttpRequest*)pAppData;
136 FILE *in = 0, *out = 0, *aux = 0;
137 int amt, got, i;
138 int wanted = 0;
139 char *z;
 
 
140 char zCmdFName[MAX_PATH];
141 char zRequestFName[MAX_PATH];
142 char zReplyFName[MAX_PATH];
143 char zCmd[2000]; /* Command-line to process the request */
144 char zHdr[4000]; /* The HTTP request header */
@@ -183,19 +190,22 @@
183 /*
184 ** The repository name is only needed if there was no open checkout. This
185 ** is designed to allow the open checkout for the interactive user to work
186 ** with the local Fossil server started via the "ui" command.
187 */
 
 
 
 
188 if( (p->flags & HTTP_SERVER_HAD_CHECKOUT)==0 ){
189 assert( g.zRepositoryName && g.zRepositoryName[0] );
190 sqlite3_snprintf(sizeof(zCmd), zCmd, "%s%s\n%s\n%s\n%s",
191 get_utf8_bom(0), zRequestFName, zReplyFName, inet_ntoa(p->addr.sin_addr),
192 g.zRepositoryName
193 );
194 }else{
195 sqlite3_snprintf(sizeof(zCmd), zCmd, "%s%s\n%s\n%s",
196 get_utf8_bom(0), zRequestFName, zReplyFName, inet_ntoa(p->addr.sin_addr)
197 );
198 }
199 aux = fossil_fopen(zCmdFName, "wb");
200 if( aux==0 ) goto end_request;
201 fwrite(zCmd, 1, strlen(zCmd), aux);
@@ -235,10 +245,12 @@
235 static void win32_scgi_request(void *pAppData){
236 HttpRequest *p = (HttpRequest*)pAppData;
237 FILE *in = 0, *out = 0;
238 int amt, got, nHdr, i;
239 int wanted = 0;
 
 
240 char zRequestFName[MAX_PATH];
241 char zReplyFName[MAX_PATH];
242 char zCmd[2000]; /* Command-line to process the request */
243 char zHdr[4000]; /* The SCGI request header */
244
@@ -265,13 +277,17 @@
265 if( got<=0 ) break;
266 fwrite(zHdr, 1, got, out);
267 wanted += got;
268 }
269 assert( g.zRepositoryName && g.zRepositoryName[0] );
 
 
 
 
270 sqlite3_snprintf(sizeof(zCmd), zCmd,
271 "\"%s\" http \"%s\" \"%s\" %s \"%s\" --scgi --nossl%s",
272 g.nameOfExe, zRequestFName, zReplyFName, inet_ntoa(p->addr.sin_addr),
273 g.zRepositoryName, p->zOptions
274 );
275 in = fossil_fopen(zReplyFName, "w+b");
276 fflush(out);
277 fossil_system(zCmd);
@@ -311,11 +327,12 @@
311 int flags /* One or more HTTP_SERVER_ flags */
312 ){
313 HANDLE hStoppedEvent;
314 WSADATA wd;
315 SOCKET s = INVALID_SOCKET;
316 SOCKADDR_IN addr;
 
317 int idCnt = 0;
318 int iPort = mnPort;
319 Blob options;
320 wchar_t zTmpPath[MAX_PATH];
321 const char *zSkin;
@@ -353,29 +370,44 @@
353 if( zSavedKey!=0 && savedKeySize>0 ){
354 blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(),
355 zSavedKey, savedKeySize);
356 }
357 #endif
358 if( WSAStartup(MAKEWORD(1,1), &wd) ){
359 fossil_fatal("unable to initialize winsock");
360 }
 
 
 
361 while( iPort<=mxPort ){
362 s = socket(AF_INET, SOCK_STREAM, 0);
 
363 if( s==INVALID_SOCKET ){
364 fossil_fatal("unable to create a socket");
365 }
366 addr.sin_family = AF_INET;
367 addr.sin_port = htons(iPort);
 
 
368 if( zIpAddr ){
369 addr.sin_addr.s_addr = inet_addr(zIpAddr);
370 if( addr.sin_addr.s_addr == (-1) ){
 
 
 
 
 
 
 
371 fossil_fatal("not a valid IP address: %s", zIpAddr);
372 }
373 }else if( flags & HTTP_SERVER_LOCALHOST ){
374 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
375 }else{
376 addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
 
377 }
378 if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){
379 closesocket(s);
380 iPort++;
381 continue;
@@ -430,11 +462,11 @@
430 /* Set the service status to running and pass the listener socket to the
431 ** service handling procedures. */
432 win32_http_service_running(s);
433 for(;;){
434 SOCKET client;
435 SOCKADDR_IN client_addr;
436 HttpRequest *pRequest;
437 int len = sizeof(client_addr);
438 int wsaError;
439
440 client = accept(s, (struct sockaddr*)&client_addr, &len);
441
--- src/winhttp.c
+++ src/winhttp.c
@@ -20,13 +20,18 @@
20 ** server to be run without any user logged on.
21 */
22 #include "config.h"
23 #ifdef _WIN32
24 /* This code is for win32 only */
25 #include <ws2tcpip.h>
26 #include <windows.h>
27 #include <process.h>
28 #include "winhttp.h"
29
30 #ifndef IPV6_V6ONLY
31 # define IPV6_V6ONLY 27 /* Because this definition is missing in MinGW */
32 #endif
33
34 /*
35 ** The HttpServer structure holds information about an instance of
36 ** the HTTP server itself.
37 */
@@ -46,11 +51,11 @@
51 */
52 typedef struct HttpRequest HttpRequest;
53 struct HttpRequest {
54 int id; /* ID counter */
55 SOCKET s; /* Socket on which to receive data */
56 SOCKADDR_IN6 addr; /* Address from which data is coming */
57 int flags; /* Flags passed to win32_http_server() */
58 const char *zOptions; /* --baseurl, --notfound, --localauth, --th-trace */
59 };
60
61 /*
@@ -135,10 +140,12 @@
140 HttpRequest *p = (HttpRequest*)pAppData;
141 FILE *in = 0, *out = 0, *aux = 0;
142 int amt, got, i;
143 int wanted = 0;
144 char *z;
145 char zIp[50];
146 DWORD nIp = sizeof(zIp);
147 char zCmdFName[MAX_PATH];
148 char zRequestFName[MAX_PATH];
149 char zReplyFName[MAX_PATH];
150 char zCmd[2000]; /* Command-line to process the request */
151 char zHdr[4000]; /* The HTTP request header */
@@ -183,19 +190,22 @@
190 /*
191 ** The repository name is only needed if there was no open checkout. This
192 ** is designed to allow the open checkout for the interactive user to work
193 ** with the local Fossil server started via the "ui" command.
194 */
195 if( WSAAddressToStringA((SOCKADDR*)&p->addr, sizeof(p->addr),
196 NULL, zIp, &nIp)!=0 ){
197 zIp[0] = 0;
198 }
199 if( (p->flags & HTTP_SERVER_HAD_CHECKOUT)==0 ){
200 assert( g.zRepositoryName && g.zRepositoryName[0] );
201 sqlite3_snprintf(sizeof(zCmd), zCmd, "%s%s\n%s\n%s\n%s",
202 get_utf8_bom(0), zRequestFName, zReplyFName, zIp, g.zRepositoryName
 
203 );
204 }else{
205 sqlite3_snprintf(sizeof(zCmd), zCmd, "%s%s\n%s\n%s",
206 get_utf8_bom(0), zRequestFName, zReplyFName, zIp
207 );
208 }
209 aux = fossil_fopen(zCmdFName, "wb");
210 if( aux==0 ) goto end_request;
211 fwrite(zCmd, 1, strlen(zCmd), aux);
@@ -235,10 +245,12 @@
245 static void win32_scgi_request(void *pAppData){
246 HttpRequest *p = (HttpRequest*)pAppData;
247 FILE *in = 0, *out = 0;
248 int amt, got, nHdr, i;
249 int wanted = 0;
250 char zIp[50];
251 DWORD nIp = sizeof(zIp);
252 char zRequestFName[MAX_PATH];
253 char zReplyFName[MAX_PATH];
254 char zCmd[2000]; /* Command-line to process the request */
255 char zHdr[4000]; /* The SCGI request header */
256
@@ -265,13 +277,17 @@
277 if( got<=0 ) break;
278 fwrite(zHdr, 1, got, out);
279 wanted += got;
280 }
281 assert( g.zRepositoryName && g.zRepositoryName[0] );
282 if (WSAAddressToStringA((SOCKADDR*)&p->addr, sizeof(p->addr),
283 NULL, zIp, &nIp)!=0){
284 zIp[0] = 0;
285 }
286 sqlite3_snprintf(sizeof(zCmd), zCmd,
287 "\"%s\" http \"%s\" \"%s\" %s \"%s\" --scgi --nossl%s",
288 g.nameOfExe, zRequestFName, zReplyFName, zIp,
289 g.zRepositoryName, p->zOptions
290 );
291 in = fossil_fopen(zReplyFName, "w+b");
292 fflush(out);
293 fossil_system(zCmd);
@@ -311,11 +327,12 @@
327 int flags /* One or more HTTP_SERVER_ flags */
328 ){
329 HANDLE hStoppedEvent;
330 WSADATA wd;
331 SOCKET s = INVALID_SOCKET;
332 SOCKADDR_IN6 addr;
333 int addrlen;
334 int idCnt = 0;
335 int iPort = mnPort;
336 Blob options;
337 wchar_t zTmpPath[MAX_PATH];
338 const char *zSkin;
@@ -353,29 +370,44 @@
370 if( zSavedKey!=0 && savedKeySize>0 ){
371 blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(),
372 zSavedKey, savedKeySize);
373 }
374 #endif
375 if( WSAStartup(MAKEWORD(2,0), &wd) ){
376 fossil_fatal("unable to initialize winsock");
377 }
378 if( flags & HTTP_SERVER_LOCALHOST ){
379 zIpAddr = "127.0.0.1";
380 }
381 while( iPort<=mxPort ){
382 DWORD ipv6only = 0;
383 s = socket(AF_INET6, SOCK_STREAM, 0);
384 if( s==INVALID_SOCKET ){
385 fossil_fatal("unable to create a socket");
386 }
387 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6only,
388 sizeof(ipv6only));
389 memset(&addr, 0, sizeof(addr));
390 addrlen = sizeof(addr);
391 if( zIpAddr ){
392 char* zIp;
393 if( strstr(zIpAddr, ".") ){
394 zIp = mprintf("::ffff:%s", zIpAddr);
395 }else{
396 zIp = mprintf("%s", zIpAddr);
397 }
398 addr.sin6_family = AF_INET6;
399 if (WSAStringToAddress(zIp, AF_INET6, NULL,
400 (struct sockaddr *)&addr, &addrlen) != 0){
401 fossil_fatal("not a valid IP address: %s", zIpAddr);
402 }
403 ((SOCKADDR_IN6*)&addr)->sin6_port = htons(iPort);
404 fossil_free(zIp);
405 }else{
406 addr.sin6_family = AF_INET6;
407 addr.sin6_port = htons(iPort);
408 memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
409 }
410 if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){
411 closesocket(s);
412 iPort++;
413 continue;
@@ -430,11 +462,11 @@
462 /* Set the service status to running and pass the listener socket to the
463 ** service handling procedures. */
464 win32_http_service_running(s);
465 for(;;){
466 SOCKET client;
467 SOCKADDR_IN6 client_addr;
468 HttpRequest *pRequest;
469 int len = sizeof(client_addr);
470 int wsaError;
471
472 client = accept(s, (struct sockaddr*)&client_addr, &len);
473

Keyboard Shortcuts

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