source: trunk/gsdl/src/w32server/netio.cpp@ 1203

Last change on this file since 1203 was 1203, checked in by sjboddie, 24 years ago

Made a few minor changes to get the local library compiling under VC++ 6.0
using the built-in STL (i.e. without the GSDL_USE_IOS_H pre-processor
definition set).

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