//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1995, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Winsock for OWL subsystem.
/// Based on work by Paul Pedriana, 70541.3223@compuserve.com
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/defs.h>
#include <owl/winsock.h>
 
namespace owl {
 
 
OWL_DIAGINFO;
 
//
//
//
DEFINE_RESPONSE_TABLE1(THostInfoWindow, TWindow)
   EV_MESSAGE(MSG_HOST_INFO_NOTIFY, DoNotification),
END_RESPONSE_TABLE;
 
//
/// The HostInfoWindow requires a HostInfoManager, so it can relay messages to it.
//
THostInfoWindow::THostInfoWindow(THostInfoManager* hostInfoManagerParent)
:
  TWindow(0, _T("HostInfo Window")),
  HostInfoManagerParent(hostInfoManagerParent)
{
  Attr.Style = 0;  // Turn off WS_CHILD (the default) style).
}
 
//
/// This is a relay function.
//
TResult THostInfoWindow::DoNotification(TParam1, TParam2 param2)
{
  HostInfoManagerParent->SetHostRequestCompleted(WSAGETASYNCERROR(param2));
  return 1;
}
 
//----------------------------------------------------------------------------
 
//
/// Constructor of THostEntry object. Initializes members describing host to 0.
//
THostEntry::THostEntry()
{
  h_name      = 0;
  h_aliases   = 0;
  h_addrtype  = 0;
  h_length    = 0;
  h_addr_list = 0;
}
 
//
/// Returns the number of pointers to addresses in the hostent (parent class of
/// THostEntry).
//
int THostEntry::GetAddressCount()
{
  int i = 0;
  while (h_addr_list[i])
    i++;
 
  return i;
}
 
//
/// This function returns the indexed internet address in unsigned long form. The
/// index must be between 0 and the number of address counts (see
/// GetAddressCount()).
///
/// \note This function is FLAWED in that it is internet addressing-specific
///  (AF_INET/PF_INET).
/// The proper way to implement this function would be to look at h_addrtype
///  and h_length to determine the nature of the address type and return
///  something useful or make a derived class that knows about each address
///  family. (...)
//
ulong THostEntry::GetNthINetAddress(int index)
{
  int addressCount = GetAddressCount();
 
  if (index >= addressCount)
    return 0;  //The caller asked for an address index that is out of range.
 
  return *((ulong*)h_addr_list[index]);
}
 
//----------------------------------------------------------------------------
// THostInfoManager
//
 
//
/// This function initializes the hidden window.
//
THostInfoManager::THostInfoManager()
:
  HostWindow(this)
{
  HostEntry            = (THostEntry*)&HostInfoBuffer;
  HostRequest          = 0;
  LastError            = 0;
  HostRequestCompleted = false;
  try {
    HostWindow.Create();
  }
  catch (...) {
    //::MessageBeep(10);  // !CQ Do something real here?
 }
}
 
//
/// With this destructor, you need to clear any pending requests before the
/// deletion.
//
THostInfoManager::~THostInfoManager()
{
  if (HostRequest && !HostRequestCompleted) // If there is an outstanding request...
    CancelHostRequest();
}
 
//
/// This function returns the name of the computer on which this program is running.
/// The name parameter is set to the name. The return value is either WINSOCK_ERROR
/// or WINSOCK_NOERROR. You can call THostInfoManager::GetLastError() to get the
/// actual error value. name is a pointer to a preallocated buffer of minimum size
/// of nameLength. nameLength should be at least N_MAX_HOST_NAME.
//
int THostInfoManager::GetHostName(char * name, int nameLength)
{
  if (TWinSockDll::gethostname(name, nameLength) == SOCKET_ERROR) {
    LastError = TWinSockDll::WSAGetLastError();
    return WINSOCK_ERROR;
  }
  return WINSOCK_NOERROR;
}
 
//
/// This function effectively converts szHostName to szHostAddress. If you have a
/// name such as "joe_schmoe@borland.com" and you want the dotted-decimal IP address
/// for it, you can call this function. This function assumes that there is enough
/// space in szHostAddress for the address. This function, like most of Windows
/// Sockets, currently works only with IP addresses. Thus, the szHostAddress is
/// always going to be dotted-decimal format in Windows Sockets.
/// Note that when using the inet_ntoa() function, the char* string returned resides
/// in Windows Sockets memory space, the szHostAddress returned is allocated and
/// owned by the caller of this function and can be manipulated any way the caller
/// wants.
/// This function returns an error value of WINSOCK_ERROR or WINSOCK_NOERROR.
//
int THostInfoManager::GetHostAddress(char * hostAddress, const char * hostName)
{
  THostEntry* tempHostEntry;
 
  int error = GetHostInfo(tempHostEntry, hostName);
  if (error == WINSOCK_ERROR)
     return error;
  return HostEntryToAddress(tempHostEntry, hostAddress);
}
 
//
/// This function effectively converts szHostName to a socket address. If you have a
/// name such as "joe_schmoe@borland.com," and you want the TSocketAddress for it,
/// you can call this function. This function, like most of Windows Sockets,
/// currently works only with IP addresses. Thus, the szAddress is always going to
/// be dotted-decimal format in Windows Sockets. The szHostName is a string
/// parameter that specifies the host of which to get the address.
/// This function returns an error value of WINSOCK_ERROR or WINSOCK_NOERROR.
//
int THostInfoManager::GetHostAddress(TSocketAddress& address, const char * hostName)
{
   THostEntry* tempHostEntry;
 
   int error = GetHostInfo(tempHostEntry, hostName);
   if (error == WINSOCK_ERROR)
      return error;
   return HostEntryToAddress(tempHostEntry, address);
}
 
//
/// The caller of this function supplies a pointer to be assigned by this function.
/// The caller need not allocate space for any THostEntry structure. Because of
/// this, the data needs to be read immediately or copied for later use. hEntry is a
/// pointer passed by reference. sAddress is a preallocated SocketAddress reference.
/// Due to the design of the socket API, the call to gethostbyaddr currently
/// requires a pointer to the Internet address, rather than a sockaddr or even a
/// sockaddr_in. Because passing a ulong pointer would most likely not work (for
/// example, if the socket API were to support something other than IP), this issue
/// is fixed by making a sockaddr interface to this API. The address is in network
/// byte ordering.
//
int THostInfoManager::GetHostInfo(THostEntry*& entry, const TSocketAddress& address)
{
  sockaddr_in* tempSockAddrIn = (sockaddr_in*)&address;
  tempSockAddrIn->sin_addr.s_addr = tempSockAddrIn->sin_addr.s_addr;
 
  entry = (THostEntry*)TWinSockDll::gethostbyaddr(
                                   (const char *)&tempSockAddrIn->sin_addr.s_addr,
                                   sizeof(ulong), PF_INET);
  if (!entry) {
    LastError = TWinSockDll::WSAGetLastError();
    return WINSOCK_ERROR;
  }
  return WINSOCK_NOERROR;
}
 
//
/// Windows Sockets can block a call until the other end finishes the transaction.
/// hEntry is a pointer passed by reference. The system will change that pointer to
/// point to an internal Windows Sockets data structure. The contents must not be
/// modified. szName is a preallocated string that holds a string. The address of
/// the host can be in string format or in binary format.
///
/// The caller of this function passes a pointer to a THostEntry struct, for
/// example:
/// \code
/// THostEntry* tempTHostEntry;
/// GetHostInfo(tempTHostEntry, "JoeShmoe@anywhere.com");
/// printf("%s", tempTHostEntry->h_name); //h_name should be "joeSchmoe@anywhere.com"
/// \endcode
int THostInfoManager::GetHostInfo(THostEntry*& entry, const char * name)
{
  entry = (THostEntry*)TWinSockDll::gethostbyname(name);
  if (!entry) {
    LastError = TWinSockDll::WSAGetLastError();
    return WINSOCK_ERROR;
  }
  return WINSOCK_NOERROR;
}
 
//
/// The caller can use this call to cancel the last pending request.
//
int THostInfoManager::CancelHostRequest(HANDLE hostRequest)
{
  if (!hostRequest)
    hostRequest = HostRequest;
 
  if (!hostRequest) {
    LastError = WSAEINVAL;  // There is no handle to use.
    return WINSOCK_ERROR;
  }
 
  if (TWinSockDll::WSACancelAsyncRequest(hostRequest) == SOCKET_ERROR) {
    LastError = TWinSockDll::WSAGetLastError();
    return WINSOCK_ERROR;
  }
 
  return WINSOCK_NOERROR;
}
 
//
/// The TheHostRequest parameter is returned to the caller with the asynchrous
/// request handle. sAddress needs to be in network byte ordering. Note that due to
/// the design of this class, you cannot have two outstanding service requests that
/// get notified directly to this class. You can use the hwnd-specific notification
/// version of this function to manage multiple requests. You can also create more
/// than one instance of this class. The service is complete when
/// HostRequestCompleted is true. Look at LastError in this case to see if there was
/// an error.
///
/// Do not issue any asynchronous calls that post to this class hwnd until the
/// previous request is completed. The alternative is to create multiple
/// THostInfoManagers or manage the call-backs yourself. See the comments about the
/// non-asynchronous version of this call (THostInfoManager::GetHostInfo) for more
/// information.
//
int THostInfoManager::GetHostInfoAsync(HANDLE& hostRequest, TSocketAddress& address)
{
  sockaddr_in* tempSockAddrIn = (sockaddr_in*)&address;
  tempSockAddrIn->sin_addr.s_addr = tempSockAddrIn->sin_addr.s_addr;
 
  HostRequestCompleted = false;
  HostRequest = hostRequest =
    TWinSockDll::WSAAsyncGetHostByAddr(HostWindow, MSG_HOST_INFO_NOTIFY,
                                    (char *)&tempSockAddrIn->sin_addr.s_addr,
                                    sizeof(ulong), PF_INET, HostInfoBuffer,
                                    MAXGETHOSTSTRUCT);
  if (!hostRequest) {
    LastError = TWinSockDll::WSAGetLastError();
    return WINSOCK_ERROR;
  }
  return WINSOCK_NOERROR;
}
 
//
/// Returns the same information as the other versions of GetHostInfoAsync. The
/// difference is that the host name can be a string, rather than a TSocketAddress.
//
int THostInfoManager::GetHostInfoAsync(HANDLE& theHostRequest, char * name)
{
  HostRequestCompleted = false;
  HostRequest = theHostRequest =
      TWinSockDll::WSAAsyncGetHostByName(HostWindow, MSG_HOST_INFO_NOTIFY, name,
                                      HostInfoBuffer, MAXGETHOSTSTRUCT);
 
  if (!HostRequest) {
    LastError = TWinSockDll::WSAGetLastError();
    return WINSOCK_ERROR;
  }
  return WINSOCK_NOERROR;
}
 
//
/// This function notifies the given window that a request has completed. nMessage
/// is the message that the wndNotify will receive. It defaults to
/// MSG_HOST_INFO_NOTIFY, which is defined in the THostInfoManager's header file.
/// The chBuffer is a pointer to the buffer that will be filled in with a hostent.
/// It needs to be at least MAXGETHOSTSTRUCT bytes. If chBuffer is 0 (or not
/// specified), the THostInfoManager's internal buffer is used. The hTheHostRequest
/// will hold a handle that the caller can use to reference the request on
/// call-back. wParam will be equal to the hService returned.
/// WSAGETSYNCERROR (lParam) holds an error, if any (0 is OK). WSAGETSYNCBUFLEN
/// (lParam) holds actual length of the buffer. When this function returns,
/// myTHostEntry holds the appropriate information. Since this information belongs
/// to this object, you can delay reading it as long as you want. Note that while
/// the sAddress should be passed in network byte ordering, the output on callback
/// is also in network ordering.
//
int THostInfoManager::GetHostInfoAsync(TWindow& wndNotify, HANDLE& hostRequest,
                                       TSocketAddress& address, uint message,
                                       char * buffer)
{
  sockaddr_in* tempSockAddrIn = (sockaddr_in*)&address;
  tempSockAddrIn->sin_addr.s_addr = tempSockAddrIn->sin_addr.s_addr;
 
  char * bufferToUse = buffer ? buffer : HostInfoBuffer;
 
  HostRequestCompleted = false;
  HostRequest = hostRequest =
    TWinSockDll::WSAAsyncGetHostByAddr(wndNotify, message,
                                    (char *)&tempSockAddrIn->sin_addr.s_addr,
                                    sizeof(ulong), PF_INET, bufferToUse,
                                    MAXGETHOSTSTRUCT);
 
  if (!hostRequest) {
    LastError = TWinSockDll::WSAGetLastError();
    return WINSOCK_ERROR;
  }
  return WINSOCK_NOERROR;
}
 
//
/// This function notifies the given window that a request has completed, wndNotify
/// is the window that will get the message that the request has completed. nMessage
/// is the message that the wndNotify will receive. It defaults to
/// MSG_HOST_INFO_NOTIFY, which is defined in the THostInfoManager's header file.
/// hTheHostRequest is the asynchrous request handle that will be a reference to the
/// request. szName is the name of the host, as in "coyote@acme.com." The chBuffer
/// is a pointer to buffer that will be filled in with a hostent. It needs to be at
/// least MAXGETHOSTSTRUCT bytes. If chBuffer is 0 (or not specified), the
/// THostInfoManager's internal buffer will be used. The returned address is in
/// network byte ordering.
//
int THostInfoManager::GetHostInfoAsync(TWindow& wndNotify, HANDLE& hostRequest, char * name,
                                       uint message, char * buffer)
{
  char * bufferToUse = buffer ? buffer : HostInfoBuffer;
 
  HostRequestCompleted = false;
  HostRequest = hostRequest =
     TWinSockDll::WSAAsyncGetHostByName(wndNotify, message, name, bufferToUse,
                                     MAXGETHOSTSTRUCT);
 
  if (!hostRequest) {
    LastError = TWinSockDll::WSAGetLastError();
    return WINSOCK_ERROR;
  }
  return WINSOCK_NOERROR;
}
 
//
/// Given a THostEntry*, this function converts it to a dotted-decimal szAddress.
/// Because Windows Sockets supports only IP addressing, this function uses IP
/// addressing and the address is always dotted-decimal. The return value is
/// WINSOCK_ERROR or WINSOCK_NOERROR.
//
int THostInfoManager::HostEntryToAddress(THostEntry* entry, char * address)
{
  in_addr    tempInAddr;
  tempInAddr.s_addr = *((ulong*)entry->h_addr);
            //else: = *((ulong*)hEntry->h_addr_list[0])
 
  char * tempAddress = TWinSockDll::inet_ntoa(tempInAddr);
  if (!tempAddress)
    return WINSOCK_ERROR;
  strcpy(address, tempAddress);
  return WINSOCK_NOERROR;
}
 
//
/// Given a THostEntry*, this function converts it to a socket address. Because
/// Windows Sockets supports only IP addressing, this function uses IP addressing
/// and the address is an INetSocketAddress. The return value is WINSOCK_ERROR or
/// WINSOCK_NOERROR.
//
int THostInfoManager::HostEntryToAddress(THostEntry* entry, TSocketAddress& address)
{
  TINetSocketAddress *addr = STATIC_CAST(TINetSocketAddress*, &address);
  addr->SetNetworkAddress(*((ulong*)entry->h_addr));
  return WINSOCK_NOERROR;
}
 
//
/// This function is called whenever an asynchronous request is completed. You may
/// want to override this function in your THostInfoManager-derived class. If you
/// do, you must call the base version.
//
void THostInfoManager::SetHostRequestCompleted(int result)
{
  int error = WSAGETASYNCERROR(result);
  if (error != 0)
    LastError = error;
  HostRequestCompleted = true;  // Of course, there may have been an error.
}
 
} // OWL namespace
 
/* ========================================================================== */
 

V570 The 'tempSockAddrIn->sin_addr.S_un.S_addr' variable is assigned to itself.

V570 The 'tempSockAddrIn->sin_addr.S_un.S_addr' variable is assigned to itself.

V570 The 'tempSockAddrIn->sin_addr.S_un.S_addr' variable is assigned to itself.

V1027 Pointer to an object of the 'TSocketAddress' class is cast to unrelated 'sockaddr_in' class.

V1027 Pointer to an object of the 'TSocketAddress' class is cast to unrelated 'sockaddr_in' class.

V1027 Pointer to an object of the 'TSocketAddress' class is cast to unrelated 'sockaddr_in' class.

V565 An empty exception handler. Silent suppression of exceptions can hide the presence of bugs in source code during testing.