root/main/trunk/greenstone2/runtime-src/src/w32server/netio.cpp @ 30565

Revision 30565, 13.1 KB (checked in by ak19, 3 years ago)

Some changes when moving from default port 80 to 8282 should not have been made

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
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 = 8282;
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 browser.