LISTEN.C

// 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 1993 - 1998 Microsoft Corporation. All Rights Reserved.
//
// MODULE: listen.c
//
// PURPOSE: Displays the "Listen" dialog box
//
// FUNCTIONS:
// CmdListen - Displays the "Listen" dialog box.
// Listen - Processes messages for "Listen" dialog box.
// MsgListenInit - Centers dialog and initializes edit controls.
// MsgListenConnected - Handles Connected message when socket is connected.
// MsgListenCommand - Process WM_COMMAND message sent to the listen box.
// CmdListenDone - Free the listen box and related data.
// CmdListenNow - Sets up listen on specified socket
//
// COMMENTS:
//
//

#include <windows.h> // required for all Windows applications
#include <windowsx.h>
#include <wsipx.h>
#include <stdlib.h>
#include <stdio.h>
#include "globals.h" // prototypes specific to this application

LRESULT CALLBACK Listen(HWND, UINT, WPARAM, LPARAM);
LRESULT MsgListenInit(HWND, UINT, WPARAM, LPARAM);
LRESULT MsgListenCommand(HWND, UINT, WPARAM, LPARAM);
LRESULT MsgListenConnected(HWND, UINT, WPARAM, LPARAM);
LRESULT CmdListenNow(HWND, WORD, WORD, HWND);
LRESULT CmdListenDone(HWND, WORD, WORD, HWND);

// Listen dialog message table definition.
MSD rgmsdListen[] =
{
{WM_COMMAND, MsgListenCommand},
{WM_INITDIALOG, MsgListenInit},
{LDM_CONNECTED, MsgListenConnected}
};

MSDI msdiListen =
{
sizeof(rgmsdListen) / sizeof(MSD),
rgmsdListen,
edwpNone
};

// Listen dialog command table definition.
CMD rgcmdListen[] =
{
{IDOK, CmdListenNow},
{IDCANCEL, CmdListenDone}
};

CMDI cmdiListen =
{
sizeof(rgcmdListen) / sizeof(CMD),
rgcmdListen,
edwpNone
};

// Module specific "globals" Used when a variable needs to be
// accessed in more than one handler function.

HFONT hfontDlg;

//
// FUNCTION: CmdListen(HWND, WORD, WORD, HWND)
//
// PURPOSE: Displays the "Listen" dialog box
//
// PARAMETERS:
// hwnd - Window handle
// wCommand - IDM_LISTEN (unused)
// wNotify - Notification number (unused)
// hwndCtrl - NULL (unused)
//
// RETURN VALUE:
//
// Always returns 0 - Message handled
//
// COMMENTS:
// To process the IDM_LISTEN message, call DialogBox() to display the
// Listen dialog box.

LRESULT CmdListen(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
{
HMENU hmenu;

SetWindowText(hwnd, "IPX Chat Server"); // Change title bar text

// Start Dialog
if(DialogBox(hInst, "ListenBox", hwnd, (DLGPROC)Listen))
{

// Dialog got a connection! Set Message to indicate
// when we have data to read, or if the connection is
// closed on us.
if (WSAAsyncSelect(sock,
hwnd,
MW_DATAREADY,
FD_READ | FD_CLOSE) == SOCKET_ERROR)
{
MessageBox(hwnd, "WSAAsyncSelect Failed!", NULL, MB_OK);
CleanUp();
return 0;
}

// Fix menus
hmenu = GetMenu(hwnd);
EnableMenuItem(hmenu, IDM_CONNECT, MF_GRAYED);
EnableMenuItem(hmenu, IDM_LISTEN, MF_GRAYED);
EnableMenuItem(hmenu, IDM_DISCONNECT, MF_ENABLED);
return 0;
}

// Listen Failed
SetWindowText(hwnd, szTitle);
return 0;
}


//
// FUNCTION: Listen(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for "Listen" dialog box.
//
// PARAMETERS:
// hdlg - window handle of the dialog box
// wMessage - type of message
// wparam - message-specific information
// lparam - message-specific information
//
// RETURN VALUE:
// TRUE - message handled
// FALSE - message not handled
//
// COMMENTS:
//
// Gets port information from user and then listens
//
// Listen when user clicks on the OK button. Kill Dialog when connection
// established.
//

LRESULT CALLBACK Listen(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
{
return DispMessage(&msdiListen, hdlg, uMessage, wparam, lparam);
}


//
// FUNCTION: MsgListenInit(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: To center dialog and limit size of edit controls and initialize
//
// PARAMETERS:
// hdlg - The window handing the message.
// uMessage - The message number. (unused).
// wparam - Message specific data (unused).
// lparam - Message specific data (unused).
//
// RETURN VALUE:
// Always returns 0 - message handled.
//
// COMMENTS:
// Set size of edit controls for the following
// Socket 4 chars (2 2-digit hex numbers)
//

LRESULT MsgListenInit(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
{

// Create a font to use
hfontDlg = CreateFont(14, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0,
VARIABLE_PITCH | FF_SWISS, "");

// Center the dialog over the application window
CenterWindow (hdlg, GetWindow (hdlg, GW_OWNER));

// Initialize Socket Addresses
SetDlgItemText(hdlg, LD_SOCKET, szListenSocket);

// Limit input to proper size strings
SendDlgItemMessage(hdlg, LD_SOCKET, EM_LIMITTEXT, 4, 0);

return (TRUE);
}

//
// FUNCTION: MsgListenConnected(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: To handle connected message when socket is connected
//
// PARAMETERS:
// hdlg - The window handing the message.
// uMessage - The message number. (unused).
// wparam - Message specific data (unused).
// lparam - Message specific data (unused).
//
// RETURN VALUE:
// Always returns 0 - message handled.
//
// COMMENTS:
// Performs accept() on incoming socket
//

LRESULT MsgListenConnected(HWND hdlg, UINT uMessage, WPARAM wparam, LPARAM lparam)
{
char outtext[128];

SetDlgItemText(hdlg,
LD_STATUS,
"Client Connected!");

SetDlgItemText(hdlg,
LD_STATUS,
"Calling accept()");

pRemAddr = (PSOCKADDR_IPX)&addr;
addrlen = sizeof(addr);

// Accept connection
if ((sock = accept(SrvSock, (struct sockaddr *)pRemAddr, &addrlen)) == INVALID_SOCKET)
{
// accept() failed -- show status and clean up dialog
sprintf(outtext, "Accept() failed, error %u",WSAGetLastError());
SetDlgItemText(hdlg,
LD_STATUS,
outtext);
closesocket(SrvSock);
WSACleanup();
EnableWindow(GetDlgItem(hdlg, IDOK), TRUE);
EnableWindow(GetDlgItem(hdlg, LD_SOCKET), TRUE);
SetFocus(GetDlgItem(hdlg, LD_SOCKET));
return(TRUE);
}

// We're connected!
GetAddrString(pRemAddr, outtext);
lstrcat(outtext, " connected!");

SetDlgItemText(hdlg,
LD_STATUS,
outtext);

EndDialog(hdlg, TRUE); // Exit the dialog
DeleteObject (hfontDlg); // Drop font
return (TRUE);
}

//
// FUNCTION: MsgListenCommand(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Process WM_COMMAND message sent to the Listen box.
//
// PARAMETERS:
// hwnd - The window handing the message.
// uMessage - The message number. (unused).
// wparam - Message specific data (unused).
// lparam - Message specific data (unused).
//
// RETURN VALUE:
// Always returns 0 - message handled.
//
// COMMENTS:
// Uses this DispCommand function defined in wndproc.c combined
// with the cmdiListen structure defined in this file to handle
// the command messages for the Listen dialog box.
//

LRESULT MsgListenCommand(HWND hwnd,
UINT uMessage,
WPARAM wparam,
LPARAM lparam)
{
return DispCommand(&cmdiListen, hwnd, wparam, lparam);
}

//
// FUNCTION: CmdListenDone(HWND, WORD, HWND)
//
// PURPOSE: Free the Listen box and related data.
//
// PARAMETERS:
// hdlg - The window handling the command.
// wCommand - The command to be handled (unused).
// wNotify - Notification number (unused)
// hwndCtrl - NULL (unused).
//
// RETURN VALUE:
// Always returns TRUE.
//
// COMMENTS:
// Cleans up sockets then calls EndDialog to finish the dialog session.
//

LRESULT CmdListenDone(HWND hdlg, WORD wCommand, WORD wNotify, HWND hwndCtrl)
{

closesocket(SrvSock); // Free any aborted socket resources
WSACleanup();
DeleteObject (hfontDlg); // Drop the font
EndDialog(hdlg, FALSE); // Exit Dialog -- rtrn false since no connection
return TRUE;
}

//
// FUNCTION: CmdListenNow(HWND, WORD, WORD, HWND)
//
// PURPOSE: Handles ID_OK message and listens on the specified socket
//
// PARAMETERS:
// hwnd - The window handling the command.
// wCommand - The command to be handled (unused).
// wNotify - Notification number (unused)
// hwndCtrl - NULL (unused).
//
// RETURN VALUE:
// Always returns TRUE.
//
// COMMENTS:
// Shows Listening address on status bar when listen is successful.
//

LRESULT CmdListenNow(HWND hdlg, WORD wCommand, WORD wNotify, HWND hwndCtrl)
{
char szXferBuffer[5];
WORD wVersionRequested;
WSADATA wsaData;
char outtext[80];

// Get Socket Address
GetDlgItemText(hdlg,
LD_SOCKET,
szXferBuffer,
13);
wVersionRequested = MAKEWORD(1, 1);

SetDlgItemText(hdlg,
LD_STATUS,
"Calling WSAStartup");

// Initializes winsock dll
if(WSAStartup(wVersionRequested, &wsaData) == SOCKET_ERROR)
{

SetDlgItemText(hdlg,
LD_STATUS,
"WSAStartup failed");
return (TRUE);
}

SetDlgItemText(hdlg,
LD_STATUS,
"WSAStartup Succeeded");

SetDlgItemText(hdlg,
LD_STATUS,
"Calling socket()");

// Allocate socket handle
SrvSock = socket(AF_IPX, // IPX Family
SOCK_SEQPACKET, // Gives message mode transfers
NSPROTO_SPX); // SPX is connection oriented transport

if(SrvSock == INVALID_SOCKET) {
SetDlgItemText(hdlg,
LD_STATUS,
"ERROR on socket()");
WSACleanup();
return(TRUE);
}

SetDlgItemText(hdlg,
LD_STATUS,
"socket() Succeeded");

// Set up socket address to bind to
memset(&addr, 0, sizeof(addr)); // Clear address
pSockAddr = (PSOCKADDR_IPX)&addr; // Set pointer
pSockAddr->sa_family = AF_IPX; // IPX Family
// Make sure socket number is in network order
AtoH(szXferBuffer, (char *)&pSockAddr->sa_socket, 2);

SetDlgItemText(hdlg,
LD_STATUS,
"Calling bind()");

// Bind to socket address
if(bind(SrvSock,
(PSOCKADDR) pSockAddr,
sizeof(SOCKADDR_IPX)) == SOCKET_ERROR)
{
SetDlgItemText(hdlg,
LD_STATUS,
"Error on bind()");
closesocket(SrvSock);
WSACleanup();
return(TRUE);
}

SetDlgItemText(hdlg,
LD_STATUS,
"bind() Succeeded");

SetDlgItemText(hdlg,
LD_STATUS,
"Calling listen()");

// Set up listen queue - this app only supports one connection so
// queue length is set to 1.
if (listen(SrvSock, 1) == SOCKET_ERROR)
{
sprintf(outtext, "FAILURE: listen() returned %u", WSAGetLastError());
SetDlgItemText(hdlg,
LD_STATUS,
outtext);
closesocket(SrvSock);
WSACleanup();
return(TRUE);
}

SetDlgItemText(hdlg,
LD_STATUS,
"listen() succeeded");

SetDlgItemText(hdlg,
LD_STATUS,
"Calling WSAAsyncSelect()");

// Specify message to be posted when client connects
if(WSAAsyncSelect(SrvSock,
hdlg,
LDM_CONNECTED,
FD_ACCEPT) == SOCKET_ERROR)
{
SetDlgItemText(hdlg,
LD_STATUS,
"WSAAsyncSelect() failed");
closesocket(SrvSock);
WSACleanup();
return(TRUE);
}

SetDlgItemText(hdlg,
LD_STATUS,
"WSAAsyncSelect() succeeded");

addrlen = sizeof(addr);

// Get full network.number.socket address
if(getsockname(SrvSock,&addr,&addrlen) == SOCKET_ERROR)
{
lstrcpy(outtext, "ERROR getsocketname()");
}
else
{
lstrcpy(outtext, "Listening on ");
GetAddrString((PSOCKADDR_IPX)&addr, outtext + lstrlen(outtext));
}

SetDlgItemText(hdlg,
LD_STATUS,
outtext);


SetFocus(GetDlgItem(hdlg, IDCANCEL)); // Give Cancel Button focus
EnableWindow(GetDlgItem(hdlg, IDOK), FALSE); // Grey OK button
EnableWindow(GetDlgItem(hdlg, LD_SOCKET), FALSE); // Grey Socket Edit control
return (TRUE);
}