www.pudn.com > globchat.zip > MISC.C, change:1997-10-05,size:18100b


// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
// PARTICULAR PURPOSE. 
// 
// Copyright (C) 1993-1997  Microsoft Corporation.  All Rights Reserved. 
// 
//  MODULE:   misc.c 
// 
//  PURPOSE:  Contains all helper functions "global" to the application. 
// 
//  FUNCTIONS: 
//    CenterWindow - Center one window over another. 
//    AtoH - Converts ascii to network order hex 
//    BtoH - Converts ascii byte to numeric 
//    deregistername - Notifies "Available" peers of clients non-availability 
//    senddatamessage - Sends a message to a client node 
//    recvdatamessage - reads an entire message 
//    UpdateClientList - Updates Client Status Listbox 
//    MakeServSock - Attempts to initialize socket for listening 
// 
//  COMMENTS: 
// 
// 
 
#include <windows.h>            // required for all Windows applications 
#include <windowsx.h> 
#include <nspapi.h> 
#include <svcguid.h> 
#include <wsipx.h> 
#include <wsnetbs.h> 
#include "globals.h"            // prototypes specific to this application 
 
 
 
// 
//  FUNCTION: CenterWindow(HWND, HWND) 
// 
//  PURPOSE:  Center one window over another. 
// 
//  PARAMETERS: 
//    hwndChild - The handle of the window to be centered. 
//    hwndParent- The handle of the window to center on. 
// 
//  RETURN VALUE: 
// 
//    TRUE  - Success 
//    FALSE - Failure 
// 
//  COMMENTS: 
// 
//    Dialog boxes take on the screen position that they were designed 
//    at, which is not always appropriate. Centering the dialog over a 
//    particular window usually results in a better position. 
// 
 
BOOL CenterWindow(HWND hwndChild, HWND hwndParent) 
{ 
    RECT    rcChild, rcParent; 
    int     cxChild, cyChild, cxParent, cyParent; 
    int     cxScreen, cyScreen, xNew, yNew; 
    HDC     hdc; 
 
    // Get the Height and Width of the child window 
    GetWindowRect(hwndChild, &rcChild); 
    cxChild = rcChild.right - rcChild.left; 
    cyChild = rcChild.bottom - rcChild.top; 
 
    // Get the Height and Width of the parent window 
    GetWindowRect(hwndParent, &rcParent); 
    cxParent = rcParent.right - rcParent.left; 
    cyParent = rcParent.bottom - rcParent.top; 
 
    // Get the display limits 
    hdc = GetDC(hwndChild); 
    cxScreen = GetDeviceCaps(hdc, HORZRES); 
    cyScreen = GetDeviceCaps(hdc, VERTRES); 
    ReleaseDC(hwndChild, hdc); 
 
    // Calculate new X position, then adjust for screen 
    xNew = rcParent.left + ((cxParent - cxChild) / 2); 
    if (xNew < 0) 
    { 
        xNew = 0; 
    } 
    else if ((xNew + cxChild) > cxScreen) 
    { 
        xNew = cxScreen - cxChild; 
    } 
 
    // Calculate new Y position, then adjust for screen 
    yNew = rcParent.top  + ((cyParent - cyChild) / 2); 
    if (yNew < 0) 
    { 
        yNew = 0; 
    } 
    else if ((yNew + cyChild) > cyScreen) 
    { 
        yNew = cyScreen - cyChild; 
    } 
 
    // Set it, and return 
    return SetWindowPos(hwndChild, 
                        NULL, 
                        xNew, yNew, 
                        0, 0, 
                        SWP_NOSIZE | SWP_NOZORDER); 
} 
 
// 
//  FUNCTION: AtoH(char *, char *, int) 
// 
//  PURPOSE:  Converts ascii string to network order hex 
// 
//  PARAMETERS: 
//    src    - pointer to input ascii string 
//    dest   - pointer to output hex 
//    destlen - size of dest 
// 
//  COMMENTS: 
// 
//    2 ascii bytes make a hex byte so must put 1st ascii byte of pair 
//    into upper nibble and 2nd ascii byte of pair into lower nibble. 
// 
 
void AtoH(char * src, char * dest, int destlen) 
{ 
    char * srcptr; 
 
    srcptr = src; 
 
    while(destlen--) 
    { 
    *dest = BtoH(*srcptr++) << 4;    // Put 1st ascii byte in upper nibble. 
    *dest++ += BtoH(*srcptr++);      // Add 2nd ascii byte to above. 
    } 
} 
 
// 
//  FUNCTION: BtoH(char *, char *, int) 
// 
//  PURPOSE:  Converts ascii byte to numeric 
// 
//  PARAMETERS: 
//    ch - ascii byte to convert 
// 
//  RETURNS: 
//    associated numeric value 
// 
//  COMMENTS: 
// 
//    Will convert any hex ascii digit to its numeric counterpart. 
//    Puts in 0xff if not a valid hex digit. 
// 
 
unsigned char BtoH(char ch) 
{ 
    if (ch >= '0' && ch <= '9') return (ch - '0');        // Handle numerals 
    if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA);  // Handle capitol hex digits 
    if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA);  // Handle small hex digits 
    return(255); 
} 
 
// 
//  FUNCTION: deregistername(char *) 
// 
//  PURPOSE:  Removes client's availability from other "AVAILABLE" clients 
// 
//  PARAMETERS: 
//    name - name to deregister 
// 
//  RETURNS: 
//    nothing 
// 
//  COMMENTS: 
// 
//    Between the time when a client connects to the server and when it starts 
//    a chat, the client is in "AVAILABLE" state.  It keeps of list of other 
//    available peers.  deregistername removes a previously available client 
//    from the lists of all the other available clients 
// 
 
void deregistername(char * name) 
{ 
    int j; 
 
    // Set up message header 
    xferbuf.hdr.signature = MYSIGNATURE; 
    xferbuf.hdr.length = REALLEN(name) + HDRSIZE; 
    xferbuf.hdr.command = DEREGISTER_NAME; 
    // Message data is simply the name 
    lstrcpy(xferbuf.data, name); 
 
    // Send to every connected client whose status is SOCKET_AVAILABLE 
    for (j = 0; j < NextFree; j++) 
    { 
        if (ConnectedSockets[j].status == SOCKSTAT_AVAILABLE) 
        { 
            senddatamessage(ConnectedSockets[j].sock, &xferbuf); 
        } 
    } 
    return; 
} 
 
// 
//  FUNCTION: senddatamessage(SOCKET, LPDATAMSG) 
// 
//  PURPOSE:  Sends a message to a client 
// 
//  PARAMETERS: 
//    sock - Client socket to send data on 
//    sendbuf - message to send 
// 
//  RETURNS: 
//    TRUE - message sent 
// 
//  COMMENTS: 
// 
//    Performs send() until entire message is sent 
// 
 
BOOL senddatamessage (SOCKET sock, LPDATAMSG sendbuf) 
{ 
    int totalbytes, bytessent; 
   int thissendsize; 
 
    bytessent = 0;                    // start count of bytessent 
    totalbytes = sendbuf->hdr.length; // read total bytes from message header 
    while(bytessent < totalbytes) 
    { 
        // We may not be able to send the entire message with a single 
      // send.  Therefore continue sending until the whole thing 
      // is gone. 
        if ((thissendsize = send(sock, 
                                (char *)sendbuf + bytessent, 
                                totalbytes - bytessent, 
                                0)) == SOCKET_ERROR) 
      { 
           // Error 
          return FALSE; 
       } 
        bytessent += thissendsize; 
    } 
 
    return TRUE; 
} 
 
// 
//  FUNCTION: recvdatamessage(LPSOCKDATA, LPDATAMSG) 
// 
//  PURPOSE:  Receives a message from a client 
// 
//  PARAMETERS: 
//    lpSockdat - pointer to sockdata struct of socket we are receiving data on. 
//    recvbuf - buffer to receive data into. 
// 
//  RETURNS: 
//    TRUE - message received 
//    FALSE - message not received 
// 
//  COMMENTS: 
//    Performs recv() until entire message is received 
// 
 
BOOL recvdatamessage (LPSOCKDATA lpSockdat, LPDATAMSG recvbuf) 
{ 
    int readsize, totalbytesread, msgsize, bytesread; 
 
    if (lpSockdat->type == SOCK_SEQPACKET) 
    { 
        // Message mode protocol!!  Just post one big read. 
        readsize = sizeof(*recvbuf); 
    } 
    else 
    { 
        // Stream mode protocol!!  Just read header...then read data (data size determined 
        // from header) 
        readsize = HDRSIZE; 
    } 
    if((totalbytesread = recv(lpSockdat->sock, (char *)recvbuf, readsize, 0)) == SOCKET_ERROR) 
    { 
        // ERROR  -- just return dropping message 
        return FALSE; 
    } 
 
    // Check for my signature at the beginning of the message 
    if(recvbuf->hdr.signature != MYSIGNATURE) 
    { 
        // I've received some data that's in mid message--drop it 
        return FALSE; 
    } 
 
    // Read size of message 
    msgsize = recvbuf->hdr.length; 
    readsize = msgsize - totalbytesread; 
 
    while(totalbytesread < msgsize) 
    { 
        // we should only get hear for stream sockets 
        if((bytesread = recv(lpSockdat->sock, 
                             (char *)recvbuf + totalbytesread, 
                             readsize, 
                             0)) == SOCKET_ERROR) 
        { 
            if (WSAGetLastError() != WSAEWOULDBLOCK) 
            { 
                // ERROR -- throw out message 
                return FALSE; 
            } 
            // If you got a WSAWOULDBLOCK error, just keep trying...it shouldn't take 
            // too much longer for the rest of the message to get here.  Let's hope 
            // we don't hog the CPU so the data doesn't get to us. 
        } 
        totalbytesread += bytesread; 
        readsize -= bytesread; 
    } 
 
    return TRUE; 
} 
 
// 
//  FUNCTION: UpdateClientList(char *, int, char *) 
// 
//  PURPOSE:  Updates Client Status List box 
// 
//  PARAMETERS: 
//    name - name of client to update 
//    status - status of client to display 
//    peername - connected peer for status = IN_SESSION 
// 
//  RETURNS: 
//    nothing 
// 
//  COMMENTS: 
//    Finds and updates client status in listbox, or adds 
//    it if client is new 
// 
 
 
void UpdateClientList(char * name, int status, char * peername) 
{ 
    int index; 
    char outtext[80]; 
 
    // Find list box entry with name in it 
    index = SendMessage(hwndClientList, 
                        LB_FINDSTRING, 
                        (WPARAM)-1, 
                        (LPARAM)name); 
 
    // Delete the entry--we'll add a new entry below 
    SendMessage(hwndClientList, LB_DELETESTRING, index, 0); 
 
    switch (status) 
    { 
        case SOCKSTAT_CLOSED:  // No new entry required.  Just return. 
            return; 
 
       case SOCKSTAT_AVAILABLE:  // build available entry 
            wsprintf(outtext, GetStringRes(IDS_AVAILABLE), name); 
       break; 
 
       case SOCKSTAT_INSESSION:  // build in_session entry 
            wsprintf(outtext, GetStringRes (IDS_SESSION), name, peername); 
       break; 
 
       case SOCKSTAT_REQSESSION: // build reqsession entry 
            wsprintf(outtext, GetStringRes(IDS_SESSION_SETUP), name, peername); 
    } 
   // Add the new list box entry to the client status list box 
    SendMessage(hwndClientList, LB_ADDSTRING, 0, (LPARAM)&outtext); 
} 
 
// 
//  FUNCTION: MakeServSock(HWND, LPSOCKDATA, LPPROTOCOL_INFO) 
// 
//  PURPOSE:  Attempts to initialize server side socket for listening 
// 
//  PARAMETERS: 
//    hwnd - handle to main window 
//    ServSocks - SOCKDATA struct to hold socket specific information 
//    lpProtBuf - PROTOCOL_INFO struct describing protocol to 
//                attempt listen on 
// 
//  RETURNS: 
//    TRUE - Listen successfully posted 
//    FALSE - Initialization failed 
// 
//  COMMENTS: 
//    Given the protocol triple in the PROTOCOL_INFO struct, we call 
//    socket(), then GetAddressByName(), then bind(), listen(), and 
//    finally WSAAsyncSelect() to get socket it appropriate state 
//    for listening.  If we fail at any point, then cleanup and do 
//    not use protocol 
// 
 
BOOL MakeServSock(HWND hwnd, LPSOCKDATA ServSocks, LPPROTOCOL_INFO lpProtBuf) 
{ 
   CSADDR_INFO CSABuf[10]; 
   DWORD dwCSABufsize = sizeof(CSABuf); 
   GUID guidNW =  SVCID_NETWARE(NWCHATID);  // Macro generates GUID using hard coded NetWare Service Type 
   GUID guidDNS = SVCID_TCP(DNSCHATID);    // Macro generates GUID using hard coded port 
   LPSOCKADDR_NB lpNBaddr; 
 
   // open socket using protocol defined by PROTOCOL_INFO structure 
   if ((ServSocks->sock = socket(lpProtBuf->iAddressFamily, 
                                       lpProtBuf->iSocketType, 
                                       lpProtBuf->iProtocol)) == SOCKET_ERROR) 
   { 
       // ERROR 
      return FALSE;  // This will reuse the current ServSocks structure 
   } 
 
   // Populate SOCKDATA structure 
   ServSocks->status = SOCKSTAT_INIT; 
   ServSocks->type = lpProtBuf->iSocketType; 
   ServSocks->protocol = lpProtBuf->iProtocol; 
   ServSocks->currconnects = 0; 
   ServSocks->lpProtocolName = lpProtBuf->lpProtocol; 
 
   // *********************************************************************** 
   // 
   //    Below we will be calling GetAddressByName with the RES_SERVICE 
   //    option in order to find the necessary sockaddr structure to use 
   //    for the following bind() call.  At this point, GetAddressByName() 
   //    only supports the DNS and the SAP/Bindery name spaces.  Ultimately 
   //    a single call to GetAddressByName will return information on 
   //    all available protocols, but this requires a central database 
   //    which is currently not available.  In the mean time we will make 
   //    name space specific calls to GetAddressByName. 
   // 
   // *********************************************************************** 
 
   switch (lpProtBuf->iAddressFamily) 
   { 
       case AF_IPX: 
           // Use SAP/Bindery Name Space 
           if (GetAddressByName(0,    // Since GUID is name space specific, we don't need to specify distinct name space. 
                                &guidNW,  // GUID defined by NetWare service type. 
                                "GLOBAL CHAT SERVER",  // This parameter is actually not used for RES_SERVICE calls. 
                                NULL,    // Since GUID implies the protocol, we don't need to specify a distinct one. 
                                RES_SERVICE,  // Specifies that we are just looking for local address to bind to. 
                                NULL,   // Currently not supported 
                                CSABuf, // Structure which will hold information for bind() call 
                                &dwCSABufsize,  // Size of CSABuf 
                                NULL,   //  Currently not supported 
                                NULL)   // Currently not supported 
                                < 1)    // We need at least one address returned in order to bind() 
           { 
               // Error--cleanup 
            closesocket(ServSocks->sock); 
            return FALSE; 
           } 
 
         // Copy sockaddr info and addresslength 
         memcpy(&ServSocks->addr, CSABuf[0].LocalAddr.lpSockaddr, sizeof(struct sockaddr)); 
         ServSocks->addrlen = CSABuf[0].LocalAddr.iSockaddrLength; 
           break; 
 
      case AF_INET: 
           // Use DNS Name Space 
           if (GetAddressByName(0,   // Since GUID is name space specific, we don't need to specify 
                                &guidDNS,  // GUID defined by TCP port number 
                                "globchat",  // This parameter is actually not used for RES_SERVICE calls 
                                NULL,    // GUID implies protocol so no need to specify 
                                RES_SERVICE,  // Specifies that we are trying to find local address to bind to 
                                NULL,  // Currently not supported 
                                CSABuf, // Results buffer 
                                &dwCSABufsize,   // Size of results buffer 
                                NULL,    // Not supported 
                                NULL)    // Not supported 
                                < 1)   // Need at least one address returned in order to bind() 
           { 
               // Error -- cleanup 
            closesocket(ServSocks->sock); 
            return FALSE; 
           } 
         // Copy sockaddr info and address length 
         memcpy(&ServSocks->addr, CSABuf[0].LocalAddr.lpSockaddr, sizeof(struct sockaddr)); 
         ServSocks->addrlen = CSABuf[0].LocalAddr.iSockaddrLength; 
           break; 
 
       case AF_NETBIOS: 
           // no netbios name space provider so we will simulate GetAddressByName() results 
         lpNBaddr = (LPSOCKADDR_NB)&ServSocks->addr; 
           SET_NETBIOS_SOCKADDR(lpNBaddr, 
                                NETBIOS_GROUP_NAME, 
                                "GLOBSERV", 
                                0); 
         ServSocks->addrlen = lpProtBuf->iMaxSockAddr; 
           break; 
 
   } 
 
   // We have an address to bind() to, so do it! 
   if (bind(ServSocks->sock, 
            &ServSocks->addr, 
           ServSocks->addrlen) == SOCKET_ERROR) 
   { 
       // Error -- cleanup 
      closesocket(ServSocks->sock); 
      return FALSE; 
   } 
 
   // Find out the specific local address 
   if (getsockname(ServSocks->sock, 
                   &ServSocks->addr, 
                   &ServSocks->addrlen) == SOCKET_ERROR) 
   { 
       // Error -- better cleanup 
       closesocket(ServSocks->sock); 
      return FALSE; 
   } 
 
   // Listen on the socket 
   if (listen(ServSocks->sock, 5) == SOCKET_ERROR) 
   { 
       // Error -- cleanup 
       closesocket(ServSocks->sock); 
      return FALSE; 
   } 
 
   // Set up window message to indicate connection 
   if (WSAAsyncSelect(ServSocks->sock, 
                      hwnd, 
                     MW_CONNECTED, 
                  FD_ACCEPT) == SOCKET_ERROR) 
   { 
       // Error -- cleanup 
      closesocket(ServSocks->sock); 
      return FALSE; 
   } 
 
   // Success!!! 
   return TRUE; 
} 
 
//--------------------------------------------------------------------------- 
// 
// FUNCTION:    GetStringRes (int id INPUT ONLY) 
// 
// COMMENTS:    Load the resource string with the ID given, and return a 
//              pointer to it.  Notice that the buffer is common memory so 
//              the string must be used before this call is made a second time. 
// 
//--------------------------------------------------------------------------- 
 
LPTSTR GetStringRes (int id) 
{ 
  static TCHAR buffer[MAX_PATH]; 
 
  buffer[0]=0; 
  LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH); 
  return buffer; 
}