source: main/trunk/greenstone2/runtime-src/src/w32server/netio.cpp@ 28758

Last change on this file since 28758 was 28758, checked in by kjdon, 7 years ago

with long return type, these didn't compile on 64 bit windows.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 KB
Line 
1/**********************************************************************
2 *
3 * netio.cpp
4 * Copyright (C) 1996
5 *
6 * A component of the fnord webserver written by bmorin@wpi.edu.
7 *
8 * Altered for use with the Greenstone digital library software by the
9 * New Zealand Digital Library Project at the University of Waikato,
10 * New Zealand.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 *********************************************************************/
27
28#include <windows.h>
29#include <stdlib.h>
30#include <stdio.h>
31#include <string.h>
32#include <memory.h>
33#pragma hdrstop
34#include "netio.h"
35#include "locate.h"
36#include "d_winsock.h"
37#include "settings.h"
38
39//Private Variables and Declarations
40
41//Max string size for a host name
42#define MAXHOSTNAME 100
43
44//Timeout for waiting between "packets" in seconds
45#define NETIO_CONN_TIMEOUT 20 //3 sec was 180 @@@@@ WJR
46
47#define HTTP_DNS_MSG WM_USER + 1
48int dns_msg_received = 0;
49int dns_msg_error = 0;
50
51DWORD LocalIPNumber;
52char LocalName[MAXHOSTNAME];
53
54//Private Function Declarations
55DWORD GetHostID();
56
57// returns 0 on success,
58// WSASYSNOTREADY, WSAVERNOTSUPPORTED, or WSAEINVAL on failure
59int InitNetIO() {
60 WSADATA Data;
61
62 // Load Winsock
63 int err = d_WSAStartup(MAKEWORD(1, 1), &Data);
64
65 // get local IP number
66 if (err == 0) LocalIPNumber = GetHostID();
67 else LocalIPNumber = INADDR_ANY;
68
69 // set the Local Name to "" for now
70 LocalName[0] = 0;
71
72 return err;
73}
74
75
76void CleanUpNetIO() {
77 //Experimental, heard this will better clean up, especialy if a call is
78 //blocking....
79 d_WSAUnhookBlockingHook();
80
81 //Clean up Winsock
82 d_WSACleanup();
83}
84
85
86void ResetNetIO() {
87 //Figure out the local name on first querry, set to "" until then...
88 LocalName[0] = 0;
89}
90
91
92DWORD GetLocalIP() {
93 return LocalIPNumber;
94}
95
96LRESULT __stdcall DNSWindowProc(HWND hWnd,UINT wMsg, WPARAM wParam, LPARAM lParam) {
97 if (wMsg == HTTP_DNS_MSG) {
98 dns_msg_received = 1;
99 dns_msg_error = WSAGETASYNCERROR(lParam);
100 return 0;
101 }
102
103 return DefWindowProc(hWnd, wMsg, wParam, lParam);
104}
105
106char *GetLocalName(HINSTANCE hInstance) {
107 // static in case it is written to after the function has finished
108 // (I did not error checking on WSACancelAsyncRequest)
109 static char buf[MAXGETHOSTSTRUCT];
110
111 if (LocalName[0] == 0) {
112 hostent *DNSResult = NULL;
113 in_addr LocalInAddr;
114
115 // if we failed to get the local IP number
116 // use the loop-back device
117 if (LocalIPNumber == INADDR_ANY) {
118 strcpy(LocalName, "127.0.0.1"); // loop-back device
119 return LocalName;
120 }
121
122 //Convert the number to an in_addr struct
123 LocalInAddr.s_addr = LocalIPNumber;
124
125 // if we fail to find the domain name we will
126 // still want the IP address
127 strcpy(LocalName, d_inet_ntoa(LocalInAddr));
128
129 // make sure they actually passed in an instance handle
130 if (hInstance == NULL) return LocalName;
131
132 // do a async domain name lookup so that we
133 // can control the timeout
134
135 // create a window class and window to handle the async messages
136 WNDCLASS wc; HWND hwndDNS;
137
138 wc.style = 0;
139 wc.lpfnWndProc = DNSWindowProc;
140 wc.cbClsExtra = 0;
141 wc.cbWndExtra = 0;
142 wc.hInstance = hInstance;
143 wc.hIcon = NULL;
144 wc.hCursor = NULL;
145 wc.hbrBackground = NULL;
146 wc.lpszMenuName = NULL;
147 wc.lpszClassName = "GSDL DNS Window";
148 if (!RegisterClass(&wc)) return LocalName;
149
150 hwndDNS = CreateWindow("GSDL DNS Window", "",
151 WS_OVERLAPPEDWINDOW, 0, 0, 100, 100,
152 NULL, NULL, hInstance, NULL);
153 if (!hwndDNS) return LocalName;
154
155 // process all messages currently on the queue
156 MSG Message;
157 while (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
158 TranslateMessage(&Message); /* translate keyboard messages */
159 DispatchMessage(&Message); /* return control to Windows NT */
160 }
161
162 //Do a async DNS lookup on the IP number
163 dns_msg_received = 0;
164 dns_msg_error = 0;
165 HANDLE asyncGetHostReq = d_WSAAsyncGetHostByAddr(
166 hwndDNS, HTTP_DNS_MSG, (char *)&(LocalInAddr),
167 4, PF_INET, buf, MAXGETHOSTSTRUCT);
168
169 if (asyncGetHostReq != NULL) {
170 // wait 5 seconds for the request to complete
171 int now = GetTickCount();
172 while ((DiffTickCounts(now, GetTickCount()) < 5000) && !dns_msg_received) {
173 if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
174 TranslateMessage(&Message); /* translate keyboard messages */
175 DispatchMessage(&Message); /* return control to Windows NT */
176 } else {
177 Sleep(1);
178 }
179 }
180 if (!dns_msg_received)
181 d_WSACancelAsyncRequest(asyncGetHostReq);
182 }
183
184 DestroyWindow(hwndDNS);
185
186 if (dns_msg_received && (dns_msg_error == 0)) {
187 //Worked, use the primary name
188 strcpy(LocalName, ((hostent *)(buf))->h_name);
189 //Convert it to lower case for cosmedic reasons
190 CharLower(LocalName);
191 }
192 }
193 return LocalName;
194}
195
196
197// returns 0 on success, and a WSA error message on failure.
198// possible error messages include:
199// WSANOTINITIALISED, WSAENETDOWN, WSAEAFNOSUPPORT, WSAEINPROGRESS, WSAEMFILE,
200// WSAENOBUFS, WSAEPROTONOSUPPORT, WSAEPROTOTYPE, WSAESOCKTNOSUPPORT,
201// WSAEADDRINUSE, WSAEINVAL, WSAEISCONN, WSAENOTSOCK, WSAEOPNOTSUPP
202
203#define MAXBINDCOUNT 4096
204int CreateListeningSocket(int &PortNum, HWND MsgWindow,
205 WORD SocketMsg, SOCKET &ServerSocket) {
206 int err = 0;
207 SOCKADDR_IN ServerSockAddr;
208 int bind_port, bind_count;
209
210 //Create the Server Socket
211 ServerSocket = d_socket(AF_INET, SOCK_STREAM, 0);
212 if (ServerSocket == INVALID_SOCKET) return d_WSAGetLastError();
213
214 bind_port = PortNum;
215 for (bind_count=0; bind_count < MAXBINDCOUNT; ++bind_count) {
216 // Set up the Server Socket Address
217 memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); //Needed?
218 ServerSockAddr.sin_port = d_htons( (WORD) bind_port);
219 ServerSockAddr.sin_family = AF_INET;
220 if (gsdl_external_access) {
221 ServerSockAddr.sin_addr.s_addr = d_htonl(INADDR_ANY);
222 }
223 else {
224 ServerSockAddr.sin_addr.s_addr = d_htonl(INADDR_LOOPBACK);
225 }
226
227
228 // Try to bind the socket with the address
229 if (d_bind(ServerSocket, (LPSOCKADDR) &ServerSockAddr,
230 sizeof(ServerSockAddr)) != SOCKET_ERROR) {
231 PortNum = bind_port;
232 break;
233 }
234
235 // make sure it failed to bind because it was
236 // already bound
237 err = d_WSAGetLastError ();
238 if (err != WSAEADDRINUSE) return err;
239
240 // Or choose another port number to try
241 if (bind_port == 80) bind_port = IPPORT_RESERVED+1;
242 else if (bind_count == 0) bind_port = 80;
243 else ++bind_port;
244 }
245
246 // return an error in we couldn't find a valid port
247 if (bind_count == MAXBINDCOUNT) return WSAEADDRINUSE;
248
249 // Start listening for connections
250 if (d_listen(ServerSocket, SOMAXCONN) == SOCKET_ERROR)
251 return d_WSAGetLastError ();
252
253 // Set up event for new connections
254 if (d_WSAAsyncSelect(ServerSocket, MsgWindow, SocketMsg, FD_ACCEPT) == SOCKET_ERROR)
255 return d_WSAGetLastError ();
256
257 return 0;
258}
259
260
261int AnswerListeningSocket(SOCKET ServerSocket, SOCKET &ClientSocket,
262 SOCKADDR_IN &ClientSockAddr, int AddrLen) {
263 if (d_WSAIsBlocking()) {
264 log_message("rejected connect due blocking\n");
265 return -1;
266 }
267
268 ClientSocket = d_accept(ServerSocket, (LPSOCKADDR) &ClientSockAddr, &AddrLen);
269 if (ClientSocket == INVALID_SOCKET) {
270 log_message("accept failed - connection lost\n");
271 return -1;
272 }
273
274 log_message("accept success - connection made\n");
275 return 0;
276}
277
278void DestroyListeningSocket(SOCKET &ServerSocket, HWND MsgWindow) {
279 //Remove any message notification
280 d_WSAAsyncSelect(ServerSocket, MsgWindow, 0, 0);
281
282 //Close the socket
283 CloseSocket(ServerSocket);
284}
285
286void CloseSocket(SOCKET &TargetSocket) {
287 if (TargetSocket != INVALID_SOCKET) {
288 //Since we're closing the socket, there's not much I can do about errors
289 //now so I'm not gonna bother checking...
290
291 //Shutdown both ends, assume we have all data...
292 d_shutdown(TargetSocket, 2);
293
294 d_closesocket(TargetSocket);
295
296 //Make sure we can't use the old handle again...
297 TargetSocket = INVALID_SOCKET;
298 }
299}
300
301int GetData(SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize,
302 int ThreadNum) {
303
304 int NumRecv;
305 int Error;
306 struct timeval Timeout;
307 fd_set SocketSet;
308
309 //Set up a socket set structure with just ClientSocket for select(..)
310 FD_ZERO(&SocketSet);
311 FD_SET(ClientSocket, &SocketSet);
312
313 //set timeout
314 Timeout.tv_sec = NETIO_CONN_TIMEOUT;
315 Timeout.tv_usec = 0;
316
317 do {
318 NumRecv = d_recv(ClientSocket, (char *) IOBuffer, IOBufferSize, 0);
319 if (NumRecv == 0) {
320 //Lost connect
321 return -1;
322
323 } else if (NumRecv == SOCKET_ERROR) {
324 Error = d_WSAGetLastError();
325 if (Error == WSAEWOULDBLOCK) {
326 NumRecv = 0;
327 //Wait for socket to be readable
328 if (d_select(0, &SocketSet, NULL, NULL, &Timeout) != 1) {
329 //Timeout
330 return -1;
331 }
332
333 } else {
334 //Assume connection terminated
335 return -1;
336 }
337 }
338 } while(NumRecv == 0);
339 return NumRecv;
340}
341
342int GetLine(text_t &OutStr, SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize,
343 int &BufferIndex, int &DataInBuffer, int ThreadNum) {
344
345 OutStr.clear();
346 char CurChar;
347
348 do {
349 if (BufferIndex == DataInBuffer) { //Need more data
350 DataInBuffer = GetData(ClientSocket, IOBuffer, IOBufferSize, ThreadNum);
351 if (DataInBuffer == -1) {
352 //Lost connect
353 return -1;
354 }
355 BufferIndex = 0;
356 }
357 CurChar = IOBuffer[BufferIndex];
358 ++BufferIndex;
359 if ((CurChar != 10) && (CurChar != 13)) {
360 OutStr.push_back(CurChar);
361 }
362 } while (CurChar != 10);
363
364 return 0;
365}
366
367int SendData(SOCKET ClientSocket, BYTE *SendBuffer, int NumToSend,
368 int ThreadNum) {
369
370 int NumSent = 0;
371 int Error;
372 struct timeval Timeout;
373 fd_set SocketSet;
374
375 char NumSentStr[50];
376 itoa(NumToSend, NumSentStr, 10);
377
378 //Set up a socket set structure with just ClientSocket for select(..)
379 FD_ZERO(&SocketSet);
380 FD_SET(ClientSocket, &SocketSet);
381 //set timeout
382 Timeout.tv_sec = NETIO_CONN_TIMEOUT;
383 Timeout.tv_usec = 0;
384
385 while (NumToSend > 0) {
386 NumSent = d_send(ClientSocket, (char *) SendBuffer + NumSent, NumToSend, 0);
387 if (NumSent == 0) {
388 //Lost connect
389 return -1;
390 }
391 else if (NumSent == SOCKET_ERROR) {
392 Error = d_WSAGetLastError();
393 if (Error == WSAEWOULDBLOCK) {
394 NumSent = 0;
395 if (d_select(0, NULL, &SocketSet, NULL, &Timeout) != 1) {
396 //Timeout
397 return -1;
398 }
399 }
400 else {
401 //Lost Connection
402 return -1;
403 }
404 }
405 NumToSend -= NumSent;
406 }
407 return 0;
408}
409
410
411/******************************************************************************/
412//Private Functions
413/******************************************************************************/
414/*-----------------------------------------------------------
415 * Function: GetHostID()
416 *
417 * Description:
418 * Get the Local IP address using the following algorithm:
419 * - get local hostname with gethostname()
420 * - attempt to resolve local hostname with gethostbyname()
421 * if that fails:
422 * - get a UDP socket
423 * - connect UDP socket to arbitrary address and port
424 * - use getsockname() to get local address
425 *
426 * Notes: Copyright by Bob Quinn, 1995, taken from his Winsock library
427 * was removed from its original module unmodified
428 */
429DWORD GetHostID () {
430 char szLclHost [MAXHOSTNAME];
431 LPHOSTENT lpstHostent;
432 SOCKADDR_IN stLclAddr;
433 SOCKADDR_IN stRmtAddr;
434 int nAddrSize = sizeof(SOCKADDR);
435 SOCKET hSock;
436 int nRet;
437
438 /* Init local address (to zero) */
439 stLclAddr.sin_addr.s_addr = INADDR_ANY;
440
441 /* Get the local hostname */
442 nRet = d_gethostname(szLclHost, MAXHOSTNAME);
443 if (nRet != SOCKET_ERROR) {
444 /* Resolve hostname for local address */
445 lpstHostent = d_gethostbyname((LPSTR)szLclHost);
446 if (lpstHostent)
447 stLclAddr.sin_addr.s_addr = *((u_long FAR*) (lpstHostent->h_addr));
448 }
449
450 /* If still not resolved, then try second strategy */
451 if (stLclAddr.sin_addr.s_addr == INADDR_ANY) {
452 /* Get a UDP socket */
453 hSock = d_socket(AF_INET, SOCK_DGRAM, 0);
454 if (hSock != INVALID_SOCKET) {
455 /* Connect to arbitrary port and address (NOT loopback) */
456 stRmtAddr.sin_family = AF_INET;
457 stRmtAddr.sin_port = d_htons(IPPORT_ECHO);
458 stRmtAddr.sin_addr.s_addr = d_inet_addr("128.127.50.1");
459 nRet = d_connect(hSock,
460 (LPSOCKADDR)&stRmtAddr,
461 sizeof(SOCKADDR));
462 if (nRet != SOCKET_ERROR) {
463 /* Get local address */
464 d_getsockname(hSock,
465 (LPSOCKADDR)&stLclAddr,
466 (int FAR*)&nAddrSize);
467 }
468 d_closesocket(hSock); /* we're done with the socket */
469 }
470 }
471 return (stLclAddr.sin_addr.s_addr);
472}
Note: See TracBrowser for help on using the repository browser.