source: gsdl/trunk/runtime-src/src/w32server/netio.cpp@ 18313

Last change on this file since 18313 was 9598, checked in by kjdon, 19 years ago

added some x++ -> ++x changes submitted by Emanuel Dejanu

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