home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Pier Shareware 6
/
The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso
/
035
/
pmics.zip
/
tcp.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1994-12-13
|
9KB
|
347 lines
/*
PMICS -- PM interface for playing chess on internet chess server
Copyright (C) 1994 Kevin Nomura
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Author can be reached at email: chow@netcom.com
*/
#ifdef TCP_SESSION
#include <strstrea.h>
#include "pmics.hh"
#include "session.hh"
#include "wcomm.hh"
#define INCL_DOSPROCESS
#define INCL_DOSFILEMGR
#define INCL_DOSDEVIOCTL
#define INCL_DOSDEVICES
#define INCL_DOSDATETIME
#define INCL_DOSQUEUES
#define INCL_DOSEXCEPTIONS
#include <os2.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <istring.hpp>
#include <iexcbase.hpp>
#define ICS_PORT_DEFAULT 5000
#define ICS_HOST_DEFAULT "chess.lm.com"
#define SE 240
#define SB 250
#define WILL 251
#define WONT 252
#define DO 253
#define DONT 254
#define IAC 255
#define ECHO 1
#define SUPPRESS_GO_AHEAD 3
#define TTYPE 24
#define NAWS 31
#define LINEMODE 34
#define ENV_VARS 36
#define CMDX(b1,b2) { char ch[4]; \
ch[0]=IAC; ch[1]=b1; ch[2]=b2; aSession->write(ch,3); }
#define CMD(b1,b2) { char ch[4]; \
ch[0]=IAC; ch[1]=b1; ch[2]=b2; write(ch,3); }
extern IString getStringOption(IString s, IString def);
extern int getIntOption(IString s, int def);
/**************************************************************************
*
* Global Variables
*
*************************************************************************/
extern strstream commStream;
extern ASession *aSession;
static char theAppName[] = "pmics";
static VOID _System TcpListen(ULONG sock);
/**************************************************************************
**************************************************************************
*
* Routines
*
**************************************************************************
*************************************************************************/
ATcpSession::ATcpSession()
{
EtherInit (); // defines sock
listenThread = new IThread(&TcpListen, (ULONG)sock);
CMD(WILL, NAWS);
CMD(DO, ECHO);
CMD(DO, SUPPRESS_GO_AHEAD);
}
/**************************************************************************
*
* EtherClose ( )
*
* Close the currently open ethernet port
*
*************************************************************************/
ATcpSession::~ATcpSession ( )
{
soclose(sock);
sock = 0;
}
/**************************************************************************
*
* EtherInit ( )
*
*************************************************************************/
void ATcpSession::EtherInit ()
{
struct sockaddr_in serveri;
IString tcphost;
int tcpport;
unsigned long icsaddr;
struct in_addr inaddr;
tcphost = getStringOption("tcphost", ICS_HOST_DEFAULT);
tcpport = getIntOption("tcpport", ICS_PORT_DEFAULT);
if (tcphost.subString(1,1).isDigits()) {
icsaddr = inet_addr(tcphost);
}
else {
struct hostent *hp;
if ((hp = gethostbyname(tcphost)) == NULL) {
throw IException(IString("Hostname cannot be resolved: ") + tcphost);
}
icsaddr = (hp->h_addr[3]<<24) |
(hp->h_addr[2]<<16) |
(hp->h_addr[1]<<8) |
(hp->h_addr[0]);
}
inaddr.s_addr = icsaddr;
ITRACE_DEVELOP("tcphost="+tcphost+
" icsaddr="+IString(inet_ntoa(inaddr))+
" tcpport="+IString(tcpport));
bzero((char *)&serveri, sizeof (serveri));
serveri.sin_family = AF_INET;
serveri.sin_port = htons(tcpport);
serveri.sin_addr.s_addr = icsaddr;
sock = socket ( AF_INET, SOCK_STREAM, 0 );
if ( sock < 0 ) {
perror("");
throw IException(IString(theAppName) + "unable to create socket.");
}
if (connect(sock,(struct sockaddr *)&serveri, sizeof(serveri)) < 0) {
perror("");
throw IException(IString(theAppName) + "unable to open connection.");
}
}
/**************************************************************************
*
* write ( value )
*
* Send *value* out the specified serial port
*
*************************************************************************/
int ATcpSession::write (char *data)
{
return write(data, strlen(data));
}
int ATcpSession::write (char *data, int len)
{
int status;
status = send ( sock , data, len, 0 );
return status;
}
/**************************************************************************
*
* EtherInt ()
*
* 4.2 interrupt routine
*
*************************************************************************/
typedef enum STATE_ {
S_START = 0,
S_IAC,
S_IAC_DO,
S_IAC_DONT,
S_IAC_WILL,
S_IAC_WONT,
S_IAC_SB,
S_IAC_SB_TTYPE,
S_IAC_SB_TTYPE_SEND,
S_IAC_SB_TTYPE_SEND_IAC
} STATE;
/*****************************************************************************/
/* thread does blocking reads against COM: and send data via window */
/* messages to the parent window as data arrives */
/*****************************************************************************/
static VOID _System TcpListen(ULONG sock_)
{
int sock = sock_;
int bytesRead;
char ch[32], *s;
int tok;
static STATE state = S_START;
static char buf[2049], cooked[2049], *putp;
IFUNCTRACE_DEVELOP();
ITRACE_DEVELOP(IString("listening to com port"));
if (! IThread::current().isPMInitialized())
IThread::current().initializePM();
while (1) {
bytesRead = recv(sock, buf, 2048, 0);
if (bytesRead <= 0) continue;
buf[bytesRead] = 0; // for debug print
ITRACE_DEVELOP(IString(bytesRead) + " bytes received from socket");
putp = cooked;
for (int i=0; i < bytesRead; i++) {
tok = (int) buf[i];
// ITRACE_DEVELOP(IString(tok));
switch(state) {
case S_START:
if (tok == IAC) state = S_IAC;
else if (tok) *putp++ = tok;
break;
case S_IAC: // IAC seen
switch(tok) {
case DO: state = S_IAC_DO; break;
case DONT: state = S_IAC_DONT; break;
case WILL: state = S_IAC_WILL; break;
case WONT: state = S_IAC_WONT; break;
case SB: state = S_IAC_SB; break;
default: state=S_START;
}
break;
case S_IAC_DO:
if (tok == TTYPE) {
ITRACE_DEVELOP("RCVD do TTYPE");
CMDX(WILL, TTYPE);
ITRACE_DEVELOP("SEND will TTYPE");
}
else if (tok == NAWS) {
ITRACE_DEVELOP("RCVD do NAWS");
s = ch;
*s++ = IAC;
*s++ = SB;
*s++ = NAWS;
*s++ = 0;
*s++ = 80;
*s++ = 0;
*s++ = 24;
*s++ = IAC;
*s++ = SE;
aSession->write(ch, 9);
ITRACE_DEVELOP("SEND suboption NAWS 80x24");
}
state = S_START;
break;
case S_IAC_SB:
if (tok == TTYPE) state = S_IAC_SB_TTYPE;
else state = S_START;
break;
case S_IAC_SB_TTYPE:
if (tok == 1) state = S_IAC_SB_TTYPE_SEND;
else state = S_START;
break;
case S_IAC_SB_TTYPE_SEND:
if (tok == IAC) state = S_IAC_SB_TTYPE_SEND_IAC;
else state = S_START;
break;
case S_IAC_SB_TTYPE_SEND_IAC:
if (tok == SE) {
ITRACE_DEVELOP("RCVD suboption TELOPT_TTYPE SEND");
// send terminal type
s = ch;
*s++ = IAC;
*s++ = SB;
*s++ = TTYPE;
*s++ = 0;
*s++ = 'v';
*s++ = 't';
*s++ = '1';
*s++ = '0';
*s++ = '0';
*s++ = IAC;
*s++ = SE;
aSession->write(ch, 11);
ITRACE_DEVELOP("SEND suboption TELOPT_TTYPE xterm");
}
state = S_START;
break;
default:
state = S_START;
break;
}
}
if (putp - cooked == 0)
continue;
commStream.clear();
commStream.write(cooked, putp - cooked);
while(1) {
try {
hComm.postEvent(MSG_COM_IN);
break;
}
catch (IInvalidParameter) {
ITRACE_DEVELOP("ComListen: exception caught, sleeping 250");
// IThread::current().sleep(250);
}
}
if (bytesRead < 16) // avoid flooding queue
// IThread::current().sleep(100);
;
}
}
#endif