home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
tmp9
/
k95d.c
< prev
next >
Wrap
C/C++ Source or Header
|
2003-04-29
|
16KB
|
550 lines
#include <stdio.h>
#ifdef NT
#include <windows.h>
#include <winsock.h>
#define strdup _strdup
#define ltoa _ltoa
#define CONFIG_FILE "k95d.cfg"
#else
#define CONFIG_FILE "k2d.cfg"
#endif
#define bzero(x,y) memset(x,0,y)
#define BSDSELECT
#define MAXPORTS 32
struct PORT
{
short id ;
int lsocket ;
int asocket ;
char * k95cmd ;
int showcmd;
int rdns;
} ports[MAXPORTS] ;
int portcount = 0 ;
#define MAXCHILDREN 256
struct CHILDREN
{
HANDLE hProcess;
int socket;
} children[MAXCHILDREN];
int childcount = 0;
void
init_children(void)
{
int i;
for ( i=0 ;i<MAXCHILDREN;i++ ) {
children[i].hProcess = INVALID_HANDLE_VALUE;
children[i].socket = (int)INVALID_HANDLE_VALUE;
}
}
void
check_children(void)
{
int i,found;
DWORD dwExit;
for (i=0, found=0; i<MAXCHILDREN && found<childcount; i++) {
if ( children[i].hProcess != INVALID_HANDLE_VALUE ) {
if (GetExitCodeProcess(children[i].hProcess, &dwExit)) {
if ( dwExit != STILL_ACTIVE ) {
closesocket(children[i].socket);
CloseHandle(children[i].hProcess);
children[i].socket = (int)INVALID_HANDLE_VALUE;
children[i].hProcess = INVALID_HANDLE_VALUE;
childcount--;
/* Do not increase found if we reduce childcount */
continue;
}
}
found++;
}
}
}
void
add_child(HANDLE hProcess, int socket)
{
int i;
for ( i=0;i<MAXCHILDREN;i++ ) {
if ( children[i].hProcess == INVALID_HANDLE_VALUE ) {
children[i].hProcess = hProcess;
children[i].socket = socket;
childcount++;
return;
}
}
}
int
ParseCmdLine( int argc, char * argv[] )
{
int len = 0, i ;
char * p = NULL ;
static struct servent *service, servrec;
int arg = 1;
if ( argc < 3 )
return 0;
ports[portcount].showcmd = SW_SHOWNORMAL;
ports[portcount].rdns = 1;
for ( arg = 1; argv[arg][0] == '-' && argv[arg][1] == '-' ; arg++ ) {
if ( !_stricmp("--maximized",argv[arg]) )
ports[portcount].showcmd = SW_SHOWMAXIMIZED;
else if ( !_stricmp("--minimized",argv[arg]) )
ports[portcount].showcmd = SW_SHOWMINIMIZED;
else if ( !_stricmp("--normal",argv[arg]) )
ports[portcount].showcmd = SW_NORMAL;
else if ( !_stricmp("--minnoactive",argv[arg]) )
ports[portcount].showcmd = SW_SHOWMINNOACTIVE;
else if ( !_stricmp("--nodns",argv[arg]) )
ports[portcount].rdns = 0;
}
p = argv[arg]; /* Was a service requested? */
if (isdigit(*p)) { /* Use socket number without lookup */
service = &servrec;
service->s_port = htons((unsigned short)atoi(p));
} else { /* Otherwise lookup the service name */
service = getservbyname(p, "tcp");
}
if ( service )
{
ports[portcount].id = service->s_port ;
}
else if ( !strcmp( "kermit", p ) )
{ /* use now assigned Kermit Service Port */
service = &servrec ;
service->s_port = htons( 1649 ) ;
}
else /* !service */
{
fprintf(stderr, "Cannot find port for service %s\n", p);
exit(2);
}
arg++;
for ( i = arg ; i < argc ; i++ )
{
len += strlen( argv[i] ) + 1 ;
}
ports[portcount].k95cmd = (char *) malloc( len ) ;
if ( !ports[portcount].k95cmd )
{
fprintf( stderr, "memory allocation error\n" ) ;
exit(1) ;
}
ports[portcount].k95cmd[0] = '\0' ;
for ( i=arg ; i<argc ; i++ )
{
strcat( ports[portcount].k95cmd, argv[i] ) ;
}
portcount++ ;
return portcount ;
}
int
ParseCfgFile( void )
{
FILE * cfgfd = NULL ;
static struct servent *service, servrec;
char cmdbuf[256], *p ;
int i ;
p = cmdbuf;
/* try and open file in local directory */
cfgfd = fopen( CONFIG_FILE, "r" ) ;
if ( !cfgfd )
return 0;
while ( !feof(cfgfd) && portcount < MAXPORTS )
{
ports[portcount].showcmd = SW_SHOWNORMAL;
ports[portcount].rdns = 1;
service = NULL ;
/* read and parse the first white space delimited string */
switch ( fscanf( cfgfd, "%s ", &cmdbuf ) )
{
case EOF:
fclose( cfgfd ) ;
return portcount ;
case 0:
/* lets assume we should just skip this line */
fscanf( cfgfd, "%[^\n]\n", cmdbuf ) ;
break;
default:
{
flag:
/* look for an optional show flag */
if ( p[0] == '-' && p[1] == '-' ) {
if ( !_stricmp("--maximized",p) )
ports[portcount].showcmd = SW_SHOWMAXIMIZED;
else if ( !_stricmp("--minimized",p) )
ports[portcount].showcmd = SW_SHOWMINIMIZED;
else if ( !_stricmp("--normal",p) )
ports[portcount].showcmd = SW_NORMAL;
else if ( !_stricmp("--minnoactive",p) )
ports[portcount].showcmd = SW_SHOWMINNOACTIVE;
else if ( !_stricmp("--nodns",p) )
ports[portcount].rdns = 0;
p = cmdbuf;
*p = '\0';
/* now read the service */
switch ( fscanf( cfgfd, "%s ", &cmdbuf ) )
{
case EOF:
fclose( cfgfd ) ;
return portcount ;
case 0:
/* lets assume we should just skip this line */
fscanf( cfgfd, "%[^\n]\n", cmdbuf ) ;
break;
default:
if ( p[0] == '-' && p[1] == '-' )
goto flag;
break;
}
}
if (isdigit(*p)) { /* Use socket number without lookup */
service = &servrec;
service->s_port = htons((unsigned short)atoi(p));
} else { /* Otherwise lookup the service name */
service = getservbyname(p, "tcp");
}
if ( service )
{
ports[portcount].id = service->s_port ;
}
else if ( !strcmp( "kermit", p ) )
{ /* use now assigned Kermit Service Port */
service = &servrec ;
ports[portcount].id = service->s_port = htons( 1649 ) ;
}
else /* ( !service ) */
{
if ( cmdbuf[0] != ';' )
fprintf( stderr, "WARNING: invalid service or port \"%s\"\n",
cmdbuf ) ;
fscanf( cfgfd, "%[^\n]\n", cmdbuf ) ;
break;
}
for ( i=0 ; i<portcount ; i++ )
{
if ( ports[i].id == ports[portcount].id )
{
fprintf( stderr, "WARNING: ignoring duplicate entry for port \"%s\"\n",
cmdbuf ) ;
fscanf( cfgfd, "%[^\n]\n", cmdbuf ) ;
break;
}
}
/* Parse the rest of the line or up to a comment */
switch ( fscanf( cfgfd, "%[^;\n]", cmdbuf ) )
{
case EOF:
case 0:
fclose( cfgfd ) ;
return portcount;
default:
ports[portcount].k95cmd = strdup(cmdbuf) ;
ports[portcount].lsocket = -1 ;
ports[portcount].asocket = -1 ;
portcount++ ;
}
}
}
}
fclose( cfgfd ) ;
return portcount ;
}
HANDLE
StartKermit( int socket, char * scriptfile, int ShowCmd, int * psockdup )
{
#ifdef NT
PROCESS_INFORMATION StartKermitProcessInfo ;
OSVERSIONINFO osverinfo ;
STARTUPINFO si ;
HANDLE sockdup = INVALID_HANDLE_VALUE ;
static char buf[512] ;
*psockdup = (int)INVALID_HANDLE_VALUE;
osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
GetVersionEx( &osverinfo ) ;
memset( &si, 0, sizeof(STARTUPINFO) ) ;
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = ShowCmd;
if (!DuplicateHandle( GetCurrentProcess(), (HANDLE) socket,
GetCurrentProcess(), &sockdup,
DUPLICATE_SAME_ACCESS, TRUE,
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS ))
{
closesocket( (int) socket ) ;
fprintf( stderr, "\nKERMIT DAEMON FATAL ERROR:\n" );
fprintf( stderr, " You are using a WinSOCK which does not allow socket handles\n");
fprintf( stderr, " to be duplicated or shared with child processes.\n\n");
fprintf( stderr, " If you are attempting to start Kermit 95 Host Mode,\n");
fprintf( stderr, " please change SESSIONS to 1 in your configuration.\n");
fprintf( stderr, "\n Press ENTER to exit...\n");
fscanf( stdin, "" ) ;
exit( 2 ) ;
}
strcpy( buf, "k95.exe -j $" ) ;
ltoa( (LONG) sockdup, buf+strlen(buf), 10 ) ;
strcat( buf, " -C \"" ) ;
strcat( buf, scriptfile ) ;
strcat( buf, "\"" ) ;
printf("Executing: %s\n",buf ) ;
if (!CreateProcess(
(LPSTR)NULL, /* start K-95 */
(LPSTR)buf, /* give it the file */
(LPSECURITY_ATTRIBUTES)NULL, /* fix if necessary */
(LPSECURITY_ATTRIBUTES)NULL, /* fix if necessary */
TRUE, /* fix if necessary */
(DWORD) CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
(LPVOID)NULL, /* fix if necessary */
(LPSTR)NULL, /* Current directory */
&si, /* Startup info, fix */
&StartKermitProcessInfo /* Process info */
))
{
CloseHandle(StartKermitProcessInfo.hThread);
*psockdup = (int)sockdup;
return (StartKermitProcessInfo.hProcess);
}
else
{
closesocket( (int) sockdup ) ;
CloseHandle(StartKermitProcessInfo.hProcess);
CloseHandle(StartKermitProcessInfo.hThread);
return(INVALID_HANDLE_VALUE);
}
#else /* NT */
#endif /* NT */
}
int
main( int argc, char * argv[] ) {
char *p;
int i, x;
int on = 1, rc = 0;
int ready_to_accept = 0 ;
static struct servent *service, servrec;
static struct hostent *host;
static struct sockaddr_in saddr;
static int saddrlen ;
#ifdef BSDSELECT
fd_set rfds;
struct timeval tv;
#endif /* BSDSELECT */
int tcpsrv_fd = -1, ttyfd = -1 ;
#ifdef NT
WSADATA data ;
HANDLE hProcess;
int sockdup = (int)INVALID_HANDLE_VALUE;
printf("Kermit-95 Daemon\n");
rc = WSAStartup( MAKEWORD( 2, 0 ), &data ) ;
if ( rc == WSAVERNOTSUPPORTED )
{
WSACleanup() ;
rc = WSAStartup( MAKEWORD( 1, 1 ), &data ) ;
}
#else /* NT */
#endif /* NT */
init_children();
ParseCmdLine( argc, argv ) ;
if ( !portcount ) /* Only use k95.cfg if there was no command line */
ParseCfgFile() ;
if ( !portcount )
{
fprintf( stderr, "Nothing to do." ) ;
exit(8) ;
}
for ( i=0; i<portcount; i++)
{
/* Set up socket structure and get host address */
bzero((char *)&saddr, sizeof(saddr));
saddr.sin_family = AF_INET ;
saddr.sin_addr.s_addr = INADDR_ANY ;
/* Get a file descriptor for the connection. */
saddr.sin_port = ports[i].id;
if ((ports[i].lsocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("TCP socket error");
exit (3);
}
errno = 0;
/* Specify the Port may be reused */
setsockopt(ports[i].lsocket, SOL_SOCKET, SO_REUSEADDR,(char *) &on, sizeof on);
/* Now bind to the socket */
#ifdef DEBUG
printf("Binding socket to port %d ... ",
ntohs((unsigned short)ports[i].id)) ;
#endif
if (bind(ports[i].lsocket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
i = errno; /* save error code */
closesocket(ports[i].lsocket) ;
ports[i].lsocket = -1 ;
ports[i].asocket = -1;
errno = i; /* and report this error */
fprintf(stderr,"tcpsrv_open bind errno","",errno);
exit(4);
}
#ifdef DEBUG
printf("Listening ...\n");
#endif
if (listen(ports[i].lsocket, 15) < 0)
{
i = errno; /* save error code */
closesocket(ports[i].lsocket) ;
ports[i].lsocket = -1 ;
ports[i].asocket = -1;
errno = i; /* and report this error */
fprintf(stderr,"tcpsrv_open listen errno","",errno);
exit(5);
}
}
printf("Servicing ports:\n");
for ( i=0;i<portcount ;i++ )
{
printf(" %d\n", ntohs((unsigned short)ports[i].id) ) ;
}
printf("Press Ctrl-C to cancel...\n");
saddrlen = sizeof(saddr) ;
#ifdef BSDSELECT
tv.tv_sec = 1L;
tv.tv_usec = 0L;
#endif /* BSDSELECT */
for ( ;; )
{
while ( !ready_to_accept )
{
check_children();
#ifdef BSDSELECT
FD_ZERO(&rfds);
for ( i=0; i<portcount;i++ )
FD_SET(ports[i].lsocket, &rfds);
if (select(FD_SETSIZE, &rfds, NULL, NULL, &tv ) > 0)
{
for ( i=0; i<portcount ; i++ )
{
if ( ready_to_accept = FD_ISSET(ports[i].lsocket, &rfds) )
break;
}
}
#else /* BSDSELECT */
#ifdef IBMSELECT
??? /* in order to make this work, we need to create an array of socket values */
ready_to_accept = (( select(&tcpsrv_fd, 1, 0, 0,1 )) == 1) ;
#endif /* IBMSELECT */
#endif /* BSDSELECT */
}
if ( ready_to_accept )
{
if ((ports[i].asocket = accept(ports[i].lsocket, (struct sockaddr *)&saddr,&saddrlen)) < 0)
{
i = errno; /* save error code */
closesocket(ports[i].lsocket) ;
ports[i].asocket = -1;
ports[i].lsocket = -1 ;
errno = i; /* and report this error */
fprintf(stderr,"tcpsrv_open accept errno","",errno);
exit(6);
}
setsockopt(ports[i].asocket, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
if (ports[i].rdns &&
(host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) != NULL)
{
printf("%s [%s] connected on port %d\n",host->h_name,
(char *)inet_ntoa(saddr.sin_addr),ntohs(ports[i].id));
} else {
printf("%s connected on port %d\n",(char *)inet_ntoa(saddr.sin_addr),
ntohs(ports[i].id));
}
/* Now start subprocess */
printf("Starting Kermit with socket %d and command %s\n",ports[i].asocket,ports[i].k95cmd);
hProcess = StartKermit(ports[i].asocket,ports[i].k95cmd, ports[i].showcmd, &sockdup);
if ( hProcess != INVALID_HANDLE_VALUE )
add_child(hProcess, sockdup);
else
closesocket(ports[i].asocket); /* we use CLOSE_SOURCE when duplicating */
continue; /* Go get the next one */
}
else
{
i = errno; /* save error code */
closesocket(ports[i].lsocket) ;
ports[i].lsocket = -1;
ports[i].asocket = -1;
errno = i; /* and report this error */
fprintf(stderr,"tcpsrv_open accept errno","",errno);
exit(7);
}
}
#ifdef NT
WSACleanup() ;
#else
#endif /* NT */
}