Fossil SCM
The "fossil server" command on windows now listens for both IPv4 and IPv6 connections.
Commit
21d5038fd097cc572c30e184dd9b79445f7284443f728edf488e56093f7a3a58
Parent
6b5cfc861a86c5c…
1 file changed
+48
-16
+48
-16
| --- src/winhttp.c | ||
| +++ src/winhttp.c | ||
| @@ -20,13 +20,18 @@ | ||
| 20 | 20 | ** server to be run without any user logged on. |
| 21 | 21 | */ |
| 22 | 22 | #include "config.h" |
| 23 | 23 | #ifdef _WIN32 |
| 24 | 24 | /* This code is for win32 only */ |
| 25 | +#include <ws2tcpip.h> | |
| 25 | 26 | #include <windows.h> |
| 26 | 27 | #include <process.h> |
| 27 | 28 | #include "winhttp.h" |
| 29 | + | |
| 30 | +#ifndef IPV6_V6ONLY | |
| 31 | +# define IPV6_V6ONLY 27 /* Because this definition is missing in MinGW */ | |
| 32 | +#endif | |
| 28 | 33 | |
| 29 | 34 | /* |
| 30 | 35 | ** The HttpServer structure holds information about an instance of |
| 31 | 36 | ** the HTTP server itself. |
| 32 | 37 | */ |
| @@ -46,11 +51,11 @@ | ||
| 46 | 51 | */ |
| 47 | 52 | typedef struct HttpRequest HttpRequest; |
| 48 | 53 | struct HttpRequest { |
| 49 | 54 | int id; /* ID counter */ |
| 50 | 55 | 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 */ | |
| 52 | 57 | int flags; /* Flags passed to win32_http_server() */ |
| 53 | 58 | const char *zOptions; /* --baseurl, --notfound, --localauth, --th-trace */ |
| 54 | 59 | }; |
| 55 | 60 | |
| 56 | 61 | /* |
| @@ -135,10 +140,12 @@ | ||
| 135 | 140 | HttpRequest *p = (HttpRequest*)pAppData; |
| 136 | 141 | FILE *in = 0, *out = 0, *aux = 0; |
| 137 | 142 | int amt, got, i; |
| 138 | 143 | int wanted = 0; |
| 139 | 144 | char *z; |
| 145 | + char zIp[50]; | |
| 146 | + DWORD nIp = sizeof(zIp); | |
| 140 | 147 | char zCmdFName[MAX_PATH]; |
| 141 | 148 | char zRequestFName[MAX_PATH]; |
| 142 | 149 | char zReplyFName[MAX_PATH]; |
| 143 | 150 | char zCmd[2000]; /* Command-line to process the request */ |
| 144 | 151 | char zHdr[4000]; /* The HTTP request header */ |
| @@ -183,19 +190,22 @@ | ||
| 183 | 190 | /* |
| 184 | 191 | ** The repository name is only needed if there was no open checkout. This |
| 185 | 192 | ** is designed to allow the open checkout for the interactive user to work |
| 186 | 193 | ** with the local Fossil server started via the "ui" command. |
| 187 | 194 | */ |
| 195 | + if( WSAAddressToStringA((SOCKADDR*)&p->addr, sizeof(p->addr), | |
| 196 | + NULL, zIp, &nIp)!=0 ){ | |
| 197 | + zIp[0] = 0; | |
| 198 | + } | |
| 188 | 199 | if( (p->flags & HTTP_SERVER_HAD_CHECKOUT)==0 ){ |
| 189 | 200 | assert( g.zRepositoryName && g.zRepositoryName[0] ); |
| 190 | 201 | 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 | |
| 193 | 203 | ); |
| 194 | 204 | }else{ |
| 195 | 205 | 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 | |
| 197 | 207 | ); |
| 198 | 208 | } |
| 199 | 209 | aux = fossil_fopen(zCmdFName, "wb"); |
| 200 | 210 | if( aux==0 ) goto end_request; |
| 201 | 211 | fwrite(zCmd, 1, strlen(zCmd), aux); |
| @@ -235,10 +245,12 @@ | ||
| 235 | 245 | static void win32_scgi_request(void *pAppData){ |
| 236 | 246 | HttpRequest *p = (HttpRequest*)pAppData; |
| 237 | 247 | FILE *in = 0, *out = 0; |
| 238 | 248 | int amt, got, nHdr, i; |
| 239 | 249 | int wanted = 0; |
| 250 | + char zIp[50]; | |
| 251 | + DWORD nIp = sizeof(zIp); | |
| 240 | 252 | char zRequestFName[MAX_PATH]; |
| 241 | 253 | char zReplyFName[MAX_PATH]; |
| 242 | 254 | char zCmd[2000]; /* Command-line to process the request */ |
| 243 | 255 | char zHdr[4000]; /* The SCGI request header */ |
| 244 | 256 | |
| @@ -265,13 +277,17 @@ | ||
| 265 | 277 | if( got<=0 ) break; |
| 266 | 278 | fwrite(zHdr, 1, got, out); |
| 267 | 279 | wanted += got; |
| 268 | 280 | } |
| 269 | 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 | + } | |
| 270 | 286 | sqlite3_snprintf(sizeof(zCmd), zCmd, |
| 271 | 287 | "\"%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, | |
| 273 | 289 | g.zRepositoryName, p->zOptions |
| 274 | 290 | ); |
| 275 | 291 | in = fossil_fopen(zReplyFName, "w+b"); |
| 276 | 292 | fflush(out); |
| 277 | 293 | fossil_system(zCmd); |
| @@ -311,11 +327,12 @@ | ||
| 311 | 327 | int flags /* One or more HTTP_SERVER_ flags */ |
| 312 | 328 | ){ |
| 313 | 329 | HANDLE hStoppedEvent; |
| 314 | 330 | WSADATA wd; |
| 315 | 331 | SOCKET s = INVALID_SOCKET; |
| 316 | - SOCKADDR_IN addr; | |
| 332 | + SOCKADDR_IN6 addr; | |
| 333 | + int addrlen; | |
| 317 | 334 | int idCnt = 0; |
| 318 | 335 | int iPort = mnPort; |
| 319 | 336 | Blob options; |
| 320 | 337 | wchar_t zTmpPath[MAX_PATH]; |
| 321 | 338 | const char *zSkin; |
| @@ -353,29 +370,44 @@ | ||
| 353 | 370 | if( zSavedKey!=0 && savedKeySize>0 ){ |
| 354 | 371 | blob_appendf(&options, " --usepidkey %lu:%p:%u", GetCurrentProcessId(), |
| 355 | 372 | zSavedKey, savedKeySize); |
| 356 | 373 | } |
| 357 | 374 | #endif |
| 358 | - if( WSAStartup(MAKEWORD(1,1), &wd) ){ | |
| 375 | + if( WSAStartup(MAKEWORD(2,0), &wd) ){ | |
| 359 | 376 | fossil_fatal("unable to initialize winsock"); |
| 360 | 377 | } |
| 378 | + if( flags & HTTP_SERVER_LOCALHOST ){ | |
| 379 | + zIpAddr = "127.0.0.1"; | |
| 380 | + } | |
| 361 | 381 | while( iPort<=mxPort ){ |
| 362 | - s = socket(AF_INET, SOCK_STREAM, 0); | |
| 382 | + DWORD ipv6only = 0; | |
| 383 | + s = socket(AF_INET6, SOCK_STREAM, 0); | |
| 363 | 384 | if( s==INVALID_SOCKET ){ |
| 364 | 385 | fossil_fatal("unable to create a socket"); |
| 365 | 386 | } |
| 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); | |
| 368 | 391 | 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){ | |
| 371 | 401 | fossil_fatal("not a valid IP address: %s", zIpAddr); |
| 372 | 402 | } |
| 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); | |
| 375 | 405 | }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)); | |
| 377 | 409 | } |
| 378 | 410 | if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){ |
| 379 | 411 | closesocket(s); |
| 380 | 412 | iPort++; |
| 381 | 413 | continue; |
| @@ -430,11 +462,11 @@ | ||
| 430 | 462 | /* Set the service status to running and pass the listener socket to the |
| 431 | 463 | ** service handling procedures. */ |
| 432 | 464 | win32_http_service_running(s); |
| 433 | 465 | for(;;){ |
| 434 | 466 | SOCKET client; |
| 435 | - SOCKADDR_IN client_addr; | |
| 467 | + SOCKADDR_IN6 client_addr; | |
| 436 | 468 | HttpRequest *pRequest; |
| 437 | 469 | int len = sizeof(client_addr); |
| 438 | 470 | int wsaError; |
| 439 | 471 | |
| 440 | 472 | client = accept(s, (struct sockaddr*)&client_addr, &len); |
| 441 | 473 |
| --- 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 |