SmaugWizard/Backup/
SmaugWizard/Backup/L/
SmaugWizard/Boards/
SmaugWizard/Building/
SmaugWizard/Corpses/
SmaugWizard/Councils/
SmaugWizard/Deity/
SmaugWizard/Gods/
SmaugWizard/MudProgs/
SmaugWizard/Player/L/
SmaugWizard/Src/
SmaugWizard/Src/res/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |				*
 * -----------------------------------------------------------|   \\._.//	*
 * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version)   |   (0...0)	*
 * -----------------------------------------------------------|    ).:.(	*
 * SMAUG (C) 1994, 1995, 1996 by Derek Snider                 |    {o o}	*
 * -----------------------------------------------------------|   / ' ' \	*
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |~'~.VxvxV.~'~*
 * Scryn, Swordbearer, Rennard, Tricops, and Gorog.           |				*
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe.    *
 ****************************************************************************/
// SmaugSocket.cpp : implementation file

#include	"stdafx.h"
#include	"SmaugWiz.h"
#include	"smaug.h"
#include	"SysData.h"
#include	"objects.h"
#include	"rooms.h"
#include	"help.h"
#include	"SmaugWizDoc.h"
#include	"SmaugSocket.h"
#include	"character.h"
#include	"descriptor.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

BEGIN_MESSAGE_MAP(CSmaugSocketWnd, CWnd)
	//{{AFX_MSG_MAP(CSmaugSocketWnd)
	//}}AFX_MSG_MAP
	ON_MESSAGE((WM_USER+502), OnHostNotify)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSmaugSocket
class	CSmaugWizDoc;

CString GetLastErrorName ();


CSmaugSocket::CSmaugSocket (CSmaugWizDoc* const pDoc)
{
	m_pDoc = pDoc;
	m_pDes = NULL;
	CreateSocketWindow ();
}

CSmaugSocket::~CSmaugSocket()
{
	ASSERT (m_pSocketWnd);
	ASSERT_VALID (m_pSocketWnd);

	m_pSocketWnd->DestroyWindow ();
	delete m_pSocketWnd;
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CSmaugSocket, CAsyncSocket)
	//{{AFX_MSG_MAP(CSmaugSocket)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif	// 0


/////////////////////////////////////////////////////////////////////////////
// CSmaugSocket member functions

void CSmaugSocket::OnAccept (int nErrorCode) 
{
	CAsyncSocket::OnAccept (nErrorCode);
	SocketAccept (nErrorCode);
}


void CSmaugSocket::OnReceive(int nErrorCode) 
{
	SocketRead (nErrorCode);
	
	CAsyncSocket::OnReceive(nErrorCode);
}

void CSmaugSocket::OnSend(int nErrorCode) 
{
	SocketWrite (nErrorCode);
	
	CAsyncSocket::OnSend(nErrorCode);
}


HANDLE CSmaugSocket::GetHostByAddr (const char* addr, int len, char* buf,
								  int buflen)
{
	return WSAAsyncGetHostByAddr (m_pSocketWnd->m_hWnd,
		WM_USER+502, addr, len, PF_INET, buf, buflen);
}


void CSmaugSocket::SocketAccept (int err)
{
	CString			Msg;
	CSmaugSocket	*pNewSock = NULL;

	// Get a pending accept
	pNewSock = new CSmaugSocket (gpDoc);
	SOCKADDR_IN	sAddr;
	int			len = sizeof (SOCKADDR_IN);
	if (! Accept (*pNewSock, (SOCKADDR*) &sAddr, &len)) {
		m_pDoc->LogString ("Couldn't accept connection", LOG_COMM);
		delete pNewSock;
		return;
	}

	// Construct a new descriptor.
	CDescriptor	*dnew;
	if (! DFreeList.IsEmpty ()) {
		dnew = (CDescriptor*) DFreeList.RemoveTail ();
		dnew->Empty ();
	}
	else dnew = new CDescriptor;

	pNewSock->m_pDes = dnew;		// make it known to the new socket

	dnew->m_pSocket = pNewSock;
	dnew->m_Connected = CON_GET_NAME;
	dnew->m_Outsize = 2000;

	dnew->m_Idle	= 0;
	dnew->lines		= 0;
	dnew->scrlen	= 24;
	dnew->port		= ntohs (sAddr.sin_port);
	dnew->user 		= STRALLOC ("unknown");
	dnew->m_pHost = NULL;
	dnew->auth_fd	= -1;
	dnew->auth_inc	= 0;
	dnew->auth_state = 0;
	dnew->newstate	= 0;
	dnew->m_PrevColor = 7;

	dnew->m_pOutbuf = new char [dnew->m_Outsize];
	dnew->m_HostAndName = new host_and_name_lookup;
	strcpy (dnew->m_HostAndName->username, "<waiting>");

	if (SysData.bNameResolving) {
		// Request the name of the caller's machine from DNS
		dnew->m_HostAndName->sin_addr = sAddr.sin_addr;
		dnew->m_HostAndName->hRequestHandle =
			pNewSock->GetHostByAddr ((char*) &dnew->m_HostAndName->sin_addr,
				sizeof (dnew->m_HostAndName->sin_addr),
				dnew->m_HostAndName->hostdata,
				sizeof (dnew->m_HostAndName->hostdata));
	}

	// Note: Smaug had site ban stuff in here somewhere

#ifdef XXXX
	CString		PAddr;
	UINT		PPort;
	if (! GetPeerName (PAddr, PPort)) {
		Msg.Format ("SocketAccept:GetPeerName failure %d", GetLastError ());
		m_pDoc->LogString (Msg);
		dnew->m_pHost = str_dup ("");
	} else {
		Msg.Format ("Sock.sinaddr:  %s", (const char*) PAddr);
		m_pDoc->LogString (Msg);

		// Request the name of the caller's machine from DNS
		dnew->m_pHost = str_dup (Msg);
		dnew->m_HostAndName->sin_addr = sock.sin_addr;
		dnew->m_HostAndName->hRequestHandle =
			WSAAsyncGetHostByAddr (hQryDlgBox, WM_NET_GETHOST,
				 (LPSTR) &dnew->m_HostAndName->sin_addr,
				sizeof dnew->m_HostAndName->sin_addr, PF_INET,
				dnew->m_HostAndName->hostdata,
				sizeof dnew->m_HostAndName->hostdata);

		// Look up the local name for this socket
		if (getsockname (sSocket, (struct sockaddr*)
		  &dnew->m_HostAndName->us, &ulen) == SOCKET_ERROR) {
			wsprintf (dnew->m_HostAndName->username,
				" (getsockname)#%d", WSAGetLastError ());
			goto failure;
		}

		// Create a socket to connect to the user's ident port
		if ((dnew->m_HostAndName->sAuth =
		  socket (PF_INET, SOCK_STREAM, AF_UNSPEC)) == INVALID_SOCKET) {
			wsprintf (dnew->m_HostAndName->username,
				" (socket)#%d", WSAGetLastError ());
			goto failure;
		}

		// Save the address of their side of the socket
		dnew->m_HostAndName->them = sock;

		// htons converts a u_short from host to network byte order.
		// 113 is the auth socket
		dnew->m_HostAndName->authsock.sin_port = htons (113);
		// Use Internet protocol
		dnew->m_HostAndName->authsock.sin_family = AF_INET;
		// Look up the other end of our socket
		dnew->m_HostAndName->authsock.sin_addr = sock.sin_addr;

		WSAAsyncSelect (dnew->m_HostAndName->sAuth, hQryDlgBox,
			WM_NET_AUTHCONNECT, FD_CONNECT|FD_READ|FD_WRITE);
		if (connect (dnew->m_HostAndName->sAuth, (struct sockaddr*)
		  &dnew->m_HostAndName->authsock,
		  sizeof (dnew->m_HostAndName->authsock)) == SOCKET_ERROR) {
			int nError = WSAGetLastError ();
			if (nError != WSAEWOULDBLOCK) {
				wsprintf (dnew->m_HostAndName->username,
					" (connect)#%d", nError);
				goto failure;
			}
		}

failure:
	}
#endif
	// Add descriptor to the list.
	DList.AddHead (dnew);

	// Update system counters
	SysData.UpdateCounters (DList.GetCount ());

	// OK now get messages from the new socket
	pNewSock->SelectReadWrite ();

	// Send the greeting.
	CHelpData	*pHelp = HelpList.Find ("GREETING", -2, 2);
	if (pHelp)
		dnew->WriteToBuffer (pHelp->GetText ());

//	Here is where smaug has authorization stuff.
//	Also number of players stuff.
//	start_auth (dnew); /* Start username authorization */
}


void CSmaugSocket::SocketRead (int err)
{
	ASSERT (m_pDes);
	CDescriptor	&Ds = *m_pDes;

	Ds.m_bFcommand	= FALSE;

	if (Ds.m_pCharacter) then
		Ds.m_pCharacter->SetTimer (0);

	if (! Ds.ReadFromDescriptor ()) {
		if (Ds.m_pCharacter) then
			save_char_obj (Ds.m_pCharacter);
		Ds.m_Outtop	= 0;
		RemoveCharacter (Ds);
	}
}


void CSmaugSocket::SocketWrite (int err)
{
	ASSERT (m_pDes);
	CDescriptor	&Ds = *m_pDes;

	if (Ds.m_bFcommand || Ds.m_Outtop > 0) {
		int iStart, nWrite;
		for (iStart = 0; iStart < Ds.m_Outtop; iStart += nWrite) {
			int nBlock = UMIN (Ds.m_Outtop - iStart, 4096);

			if ((nWrite =
			  Send (Ds.m_pOutbuf + iStart, nBlock)) == SOCKET_ERROR) {
				if (GetLastError () != WSAEWOULDBLOCK) {
					m_pDoc->LogStringf (LOG_COMM, LEVEL_LOG,
						"WriteToDescriptor:%s", NCCP GetLastErrorName ());
					if (Ds.m_pCharacter != NULL) then
						save_char_obj (Ds.m_pCharacter);
					RemoveCharacter (Ds);
				}
				break;
			}
			SysData.AddSentBytes (nWrite);
		}

		// It might be better at this point to resend if we
		// got EWOULDBLOCK, but we throw all data away...
		Ds.m_Outtop = 0;
	}
}


void CSmaugSocket::OnConnect(int nErrorCode) 
{
	// TODO: Add your specialized code here and/or call the base class
	
	CAsyncSocket::OnConnect(nErrorCode);
}


LRESULT CSmaugSocket::GetHost (WPARAM wParam, LPARAM lParam)
{
	ASSERT (m_pDes);
	CString	Msg;

	if (! m_pDes) {
		bug ("Get Host info for null descriptor");
		return FALSE;
	}

	WORD	wError = WSAGETASYNCERROR (lParam);
	if (wError) {
		char *p = " (Unknown Error)";

		if (wError == WSAHOST_NOT_FOUND) then
			p = " Host Not Found)";
		else if (wError == WSATRY_AGAIN) then
			p = " (Host not found, or Server Failure)";
		else if (wError == WSANO_RECOVERY) then
			p = " (Former, Refused, or Not Implemented)";
		else if (wError == WSANO_DATA) then
			p = " (Valid name, no data record)";
		else if (wError == WSANO_DATA) then
			p = " (No Address)";

		Msg.Format ("%s %s", m_pDes->m_pHost, p);
		delete [] m_pDes->m_pHost;
		m_pDes->m_pHost = str_dup (Msg);
	} else {
		Msg.Format ("@%s", ((hostent*)
			 (m_pDes->m_HostAndName->hostdata))->h_name);
		delete [] m_pDes->m_pHost;
		m_pDes->m_pHost = str_dup (Msg);
	}

	return TRUE;
}



BOOL CSmaugSocket::SelectReadWrite ()
{
	if (! AsyncSelect (FD_READ | FD_WRITE | FD_CLOSE)) {
		CString	Msg;
		Msg.Format ("CSmaugSocket::SelectReadWrite: Select "
			"failure %d on client socket.", GetLastError ());
		m_pDoc->LogString (Msg, LOG_COMM);
		return FALSE;
	}

	return TRUE;
}


void CSmaugSocket::CreateSocketWindow ()
{
	m_pSocketWnd = new CSmaugSocketWnd (this);
	m_pSocketWnd->m_hWnd = NULL;
	if (!m_pSocketWnd->CreateEx(0, AfxRegisterWndClass(0),
		_T("Socket Notification Sink"),
		WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL))
	{
		TRACE0("Warning: unable to create SmaugSocket notify window!\n");
		AfxThrowResourceException();
	}
	ASSERT(m_pSocketWnd->m_hWnd != NULL);
	ASSERT(CWnd::FromHandlePermanent(m_pSocketWnd->m_hWnd) == m_pSocketWnd);
}


CString GetLastErrorName ()
{
	CString	s = "Unknown";

	switch (GetLastError ()) {
		case WSAEINTR:
			s = "WSAEINTR";
			break;
		case WSAEBADF:
			s = "WSAEBADF";
			break;
		case WSAEACCES:
			s = "WSAEACCES";
			break;
		case WSAEFAULT:
			s = "WSAEFAULT";
			break;
		case WSAEINVAL:
			s = "WSAEINVAL";
			break;
		case WSAEMFILE:
			s = "WSAEMFILE";
			break;
		case WSAEWOULDBLOCK:
			s = "WSAEWOULDBLOCK";
			break;
		case WSAEINPROGRESS:
			s = "WSAEINPROGRESS";
			break;
		case WSAEALREADY:
			s = "WSAEALREADY";
			break;
		case WSAENOTSOCK:
			s = "WSAENOTSOCK";
			break;
		case WSAEDESTADDRREQ:
			s = "WSAEDESTADDRREQ";
			break;
		case WSAEMSGSIZE:
			s = "WSAEMSGSIZE";
			break;
		case WSAEPROTOTYPE:
			s = "WSAEPROTOTYPE";
			break;
		case WSAENOPROTOOPT:
			s = "WSAENOPROTOOPT";
			break;
		case WSAEPROTONOSUPPORT:
			s = "WSAEPROTONOSUPPORT";
			break;
		case WSAESOCKTNOSUPPORT:
			s = "WSAESOCKTNOSUPPORT";
			break;
		case WSAEOPNOTSUPP:
			s = "WSAEOPNOTSUPP";
			break;
		case WSAEPFNOSUPPORT:
			s = "WSAEPFNOSUPPORT";
			break;
		case WSAEAFNOSUPPORT:
			s = "WSAEAFNOSUPPORT";
			break;
		case WSAEADDRINUSE:
			s = "WSAEADDRINUSE";
			break;
		case WSAEADDRNOTAVAIL:
			s = "WSAEADDRNOTAVAIL";
			break;
		case WSAENETDOWN :
			s = "WSAENETDOWN";
			break;
		case WSAENETUNREACH:
			s = "WSAENETUNREACH";
			break;
		case WSAENETRESET:
			s = "WSAENETRESET";
			break;
		case WSAECONNABORTED:
			s = "WSAECONNABORTED";
			break;
		case WSAECONNRESET:
			s = "WSAECONNRESET";
			break;
		case WSAENOBUFS:
			s = "WSAENOBUFS";
			break;
		case WSAEISCONN:
			s = "WSAEISCONN";
			break;
		case WSAENOTCONN:
			s = "WSAENOTCONN";
			break;
		case WSAESHUTDOWN:
			s = "WSAESHUTDOWN";
			break;
		case WSAETOOMANYREFS:
			s = "WSAETOOMANYREFS";
			break;
		case WSAETIMEDOUT:
			s = "WSAETIMEDOUT";
			break;
		case WSAECONNREFUSED:
			s = "WSAECONNREFUSED";
			break;
		case WSAELOOP:
			s = "WSAELOOP";
			break;
		case WSAENAMETOOLONG:
			s = "WSAENAMETOOLONG";
			break;
		case WSAEHOSTDOWN:
			s = "WSAEHOSTDOWN";
			break;
		case WSAEHOSTUNREACH:
			s = "WSAEHOSTUNREACH";
			break;
		case WSAENOTEMPTY:
			s = "WSAENOTEMPTY";
			break;
		case WSAEPROCLIM:
			s = "WSAEPROCLIM";
			break;
		case WSAEUSERS:
			s = "WSAEUSERS";
			break;
		case WSAEDQUOT:
			s = "WSAEDQUOT";
			break;
		case WSAESTALE:
			s = "WSAESTALE";
			break;
		case WSAEREMOTE:
			s = "WSAEREMOTE";
			break;
		case WSAEDISCON:
			s = "WSAEDISCON";
			break;
		case WSASYSNOTREADY:
			s = "WSASYSNOTREADY";
			break;
		case WSAVERNOTSUPPORTED:
			s = "WSAVERNOTSUPPORTED";
			break;
		case WSANOTINITIALISED:
			s = "WSANOTINITIALISED";
			break;
	}
	return s;
}



LRESULT	CSmaugSocketWnd::OnHostNotify (WPARAM wParam, LPARAM lParam)
{
	return m_pSock->GetHost (wParam, lParam);
}