char *ckonetv = "OS/2 Network support, 5A(040) 4 Oct 94"; /* C K O N E T -- OS/2-specific network support */ /* COPYRIGHT NOTICE: Copyright (C) 1985, 1994, Trustees of Columbia University in the City of New York. The C-Kermit software may not be, in whole or in part, licensed or sold for profit as a software product itself, nor may it be included in or distributed with commercial products or otherwise distributed by commercial concerns to their clients or customers without written permission of the Office of Kermit Development and Distribution, Columbia University. This copyright notice must not be removed, altered, or obscured. */ /* Currently supported network services: - DECnet (PATHWORKS) LAT (support resides in this module) - TCP/IP Telnet (for which this module acts as a front end to ckcnet.c) - Named pipes [Jeffrey Altman ] - NETBIOS [Jeffrey Altman ] */ #include "ckcdeb.h" #include "ckcker.h" #include "ckuusr.h" #include "ckcasc.h" #define EXTERN #include "ckcnet.h" /* include ckonet.h and this includes ckotcp.h */ #include #include #include extern int ttnproto, tt_type; extern char *tn_term; char tcpname[512]; /* For SHOW NET */ #ifndef NETCONN /* Network support not defined. Dummy functions here in case #ifdef's forgotten elsewhere. */ int /* Open network connection */ os2_netopen(name, lcl, nett) char *name; int *lcl, nett; { return(-1); } int /* Close network connection */ os2_netclos() { return(-1); } int /* Check network input buffer */ os2_nettchk() { return(-1); } int /* Flush network input buffer */ os2_netflui() { return(-1); } int /* Send network BREAK */ os2_netbreak() { return(-1); } int /* Input character from network */ os2_netinc(timo) int timo; { } int /* Output character to network */ os2_nettoc(c) int c; { return(-1); } int os2_nettol(s,n) char *s; int n; { return(-1); } #else /* NETCONN is defined (rest of this module...) */ #ifndef __32BIT__ #define far _far #define near _near #define pascal _pascal #endif #ifdef NPIPE #include #define INCL_DOSNMPIPES extern char pipename[PIPENAML+1]; #endif /* NPIPE */ #define INCL_NOPM #define INCL_DOSPROCESS #define INCL_DOSMODULEMGR #define INCL_DOSSEMAPHORES #define INCL_ERRORS #include #undef COMMENT int tcp_avail = 0; int dnet_avail = 0; USHORT netbiosAvail = 0; #ifdef DECNET #ifdef __32BIT__ #pragma seg16(lcb) #pragma seg16(latinfo) #pragma seg16(inbuf) #else /* __32BIT__ */ #define _Seg16 #define APIENTRY16 APIENTRY #define APIRET16 USHORT #endif /* __32BIT__ */ #include "ckolat.h" static APIRET16 (* APIENTRY16 LATENTRY)(struct lat_cb * _Seg16) = NULL; static struct lat_cb lcb; static struct lat_info latinfo; #endif /* DECNET */ /* N E T I N C - Input Buffer */ static unsigned long size = 0, pos = 0; static unsigned char inbuf[MAXRP+1] ; extern int duplex, debses, seslog, ttyfd, quiet; /* External variables */ extern int nettype; extern char ttname[] ; extern char myhost[] ; #ifdef NPIPE HPIPE hPipe = 0 ; UCHAR PipeName[PIPENAML+1]; /* Pipe name */ #endif /* NPIPE */ #ifdef CK_NETBIOS #include "ckonbi.h" extern PNCB pWorkNCB ; extern PNCB pListenNCB ; extern PNCB pRecvNCB ; extern PNCB pSendNCB[MAXWS] ; extern BYTE NetBiosLSN ; extern HEV hevNetBiosLSN ; extern UCHAR NetBiosRemote[NETBIOS_NAME_LEN+1] ; extern UCHAR NetBiosName[NETBIOS_NAME_LEN+1] ; extern UCHAR NetBiosAdapter ; extern TID ListenThreadID ; extern BYTE NetBiosRecvBuf[MAXRP] ; extern BYTE * NetBiosSendBuf[MAXWS] ; extern USHORT MaxCmds,MaxSess,MaxNames ; void NetbiosListenThread(void * pArgList); #endif /* CK_NETBIOS */ /* N E T O P E N -- Open a network connection. */ /* Returns 0 on success, -1 on failure. */ /* Calling conventions same as ttopen(), except third argument is network type rather than modem type. Designed to be called from within ttopen. */ int os2_netopen(name, lcl, nett) char *name; int *lcl, nett; { #ifdef NPIPE ULONG OpenMode; ULONG PipeMode; ULONG OutBufSize; ULONG InBufSize; ULONG TimeOut; ULONG ActionTaken ; ULONG OpenFlag ; ULONG BytesRead ; AVAILDATA AvailData ; ULONG PipeState ; #endif /* NPIPE */ int rc = -1; #ifdef CK_NETBIOS if ( nettype == NET_BIOS ) { ULONG PostCount ; UCHAR RemoteName[NETBIOS_NAME_LEN+1] = " \0" ; if ( !netbiosAvail ) return -1 ; strncpy( RemoteName, name, strlen(name) ) ; /* strcpy( name, RemoteName ) ; */ /* name will now be 16 characters */ if ( NetBiosLSN > 0 /* Make sure a handle doesn't exist */ || ttyfd > -1 ) return 0 ; DosResetEventSem( hevNetBiosLSN, &PostCount ) ; if ( !strcmp( "* ", RemoteName ) ) { /* Server Mode */ if ( pListenNCB->basic_ncb.bncb.ncb_retcode == NB_COMMAND_IN_PROCESS) return 0 ; printf("Listening for a NetBios connection\n") ; rc = NCBListen( NetbeuiAPI, pListenNCB, NetBiosAdapter, NetBiosName, RemoteName, NB_RECV_TIMEOUT, NB_SEND_TIMEOUT, FALSE ) ; if ( rc ) return -1 ; ttyfd = NetBiosLSN = 0 ; ListenThreadID = _beginthread( &NetbiosListenThread, 0, 16384, 0 ); if ( ListenThreadID == -1 ) { Dos16SemWait( pListenNCB->basic_ncb.ncb_semaphore, SEM_INDEFINITE_WAIT ) ; switch (pListenNCB->basic_ncb.bncb.ncb_retcode) { case NB_COMMAND_SUCCESSFUL: ttyfd = NetBiosLSN = pListenNCB->basic_ncb.bncb.ncb_lsn ; return 0 ; break; default: return -1 ; } } return 0 ; } else { /* Remote Mode */ int oldalarm = alarm(0) ; printf("Calling \"%s\" via NetBios\n", RemoteName ) ; rc = NCBCall( NetbeuiAPI, pWorkNCB, NetBiosAdapter, NetBiosName, RemoteName, NB_RECV_TIMEOUT, NB_SEND_TIMEOUT, FALSE ) ; rc = Dos16SemWait( pWorkNCB->basic_ncb.ncb_semaphore, SEM_INDEFINITE_WAIT ) ; if (rc) return -1 ; switch ( pWorkNCB->basic_ncb.bncb.ncb_retcode ) { case NB_COMMAND_SUCCESSFUL: strncpy( NetBiosRemote, pWorkNCB->basic_ncb.bncb.ncb_callname, NETBIOS_NAME_LEN ) ; ttyfd = NetBiosLSN = pWorkNCB->basic_ncb.bncb.ncb_lsn ; NCBReceive( NetbeuiAPI, pRecvNCB, NetBiosAdapter, NetBiosLSN, NetBiosRecvBuf, sizeof(NetBiosRecvBuf), FALSE ) ; Dos16SemClear(pListenNCB->basic_ncb.ncb_semaphore ) ; DosPostEventSem( hevNetBiosLSN ) ; rc = 0 ; break; case ERROR_FILE_NOT_FOUND: case ERROR_ACCESS_DENIED: case ERROR_INVALID_PARAMETER: default: rc = -1 ; } alarm(oldalarm) ; return rc ; } } #endif /* CK_NETBIOS */ #ifdef NPIPE if ( nettype == NET_PIPE ) { if ( hPipe ) { /* Make sure a pipe isn't open */ char buffer[64]; rc = DosPeekNPipe(hPipe, buffer, sizeof(buffer), &BytesRead, &AvailData, &PipeState); switch ( rc ) { case NO_ERROR: return 0 ; case ERROR_BAD_PIPE: case ERROR_PIPE_NOT_CONNECTED: ttclos(0); break; default: break; } } if ( *name == '\0' ) { strcpy( PipeName, "\\PIPE\\C-Kermit for OS2" ) ; } else { strcpy( PipeName, name ) ; } if ( PipeName[0] == '\\' && PipeName[1] == '\\' ) { /* Client Mode */ OpenFlag = OPEN_ACTION_OPEN_IF_EXISTS ; OpenMode = OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE ; if (PipeName[2] == '.' && PipeName[3] == '\\') { /* Internal use. */ int i, n = strlen(PipeName); for (i = 3; i <= n; i++) PipeName[i-3] = PipeName[i]; } rc = DosOpen( PipeName, &hPipe, &ActionTaken, 0, 0, OpenFlag, OpenMode, 0 ) ; switch (rc) { case NO_ERROR: ttyfd = hPipe ; DosSetNPHState( hPipe, NP_NOWAIT | NP_READMODE_BYTE ) ; printf( "\nNamed Pipe %s open.\nConnection to server complete.\n", PipeName ); break; case ERROR_BAD_NETPATH: printf("\nInvalid Server specified in Pipe Name: %s\n", PipeName ) ; break; case ERROR_PATH_NOT_FOUND: case ERROR_FILE_NOT_FOUND: printf("\nNonexistent Named Pipe: %s\n", PipeName ) ; break; case ERROR_PIPE_BUSY: printf("\nNamed Pipe Already in Use: %s\n", PipeName ) ; break; default: debug( F101, "DosOpen error: return code","",rc) ; printf( "\nDosOpen error: return code = %ld\n",rc ) ; } } else { /* Server Mode */ OpenMode = NP_ACCESS_DUPLEX | NP_INHERIT | NP_NOWRITEBEHIND | NP_TYPE_BYTE | NP_READMODE_BYTE ; PipeMode = NP_NOWAIT | 0x01; OutBufSize = MAXSP + 4 ; InBufSize = MAXRP + 4 ; TimeOut = 10000; rc = DosCreateNPipe( PipeName, &hPipe, OpenMode, PipeMode, OutBufSize, InBufSize, TimeOut); switch (rc) { case NO_ERROR: ttyfd = hPipe ; rc = DosConnectNPipe( hPipe ) ; if (rc == NO_ERROR || rc == ERROR_PIPE_NOT_CONNECTED) { printf("\nNamed Pipe %s created.\nWaiting for client connection ...\n\n", PipeName ) ; rc = 0 ; } else { debug( F101,"DosConnectNPipe error: return code","",rc) ; printf("\nDosConnectNPipe error: return code = %ld\n", rc); } break; case ERROR_PATH_NOT_FOUND: printf("\nInvalid Pipe Name: %s\n", PipeName ) ; break; case ERROR_PIPE_BUSY: printf("\nNamed Pipe Already in Use: %s\n", PipeName ) ; break; default: debug( F101,"DosCreateNPipe error: return code","",rc) ; printf("\nDosCreateNPipe error: return code = %ld\n", rc); } } return ( rc ? -1 : 0 ) ; } #endif /* NPIPE */ #ifdef TCPSOCKET if ( nettype == NET_TCPB ) { if (!tcp_avail) return -1 ; rc = netopen(name, lcl, nett); #ifdef COMMENT if ( rc > -1) rc = tn_ini(); #endif /* COMMENT */ return(rc); } #endif /* TCPSOCKET */ #ifdef DECNET if ( nettype == NET_DEC ) { if ( LATENTRY == NULL ) return -1; ttnproto = NP_LAT; printf("Trying %s ... ", name); memset( &lcb, 0, sizeof(struct lat_cb) ) ; lcb.LatFunction = START_SESSION; lcb.BufferSize = strlen(name); lcb.BufferPtr = (void * _Seg16) name; LATENTRY(&lcb); ttyfd = lcb.SessionHandle; printf(lcb.LatStatus ? "failed.\n" : "OK.\n"); rc = (lcb.LatStatus == 0) ? 0 : -1; } #endif /* DECNET */ return rc; } /* N E T C L O S -- Close current network connection. */ int os2_netclos() { int rc = 0; if (ttyfd < 0) /* Was open? */ return(rc); /* Wasn't. */ #ifdef CK_NETBIOS if ( nettype == NET_BIOS ) { ULONG PostCount ; if ( NetBiosLSN >= 0 ) { NCB CleanupNCB ; int i ; if ( pWorkNCB->basic_ncb.bncb.ncb_retcode == NB_COMMAND_IN_PROCESS ) NCBCancel( NetbeuiAPI, &CleanupNCB, NetBiosAdapter, pWorkNCB ) ; if ( pListenNCB->basic_ncb.bncb.ncb_retcode == NB_COMMAND_IN_PROCESS ) { NCBCancel( NetbeuiAPI, &CleanupNCB, NetBiosAdapter, pListenNCB ) ; DosWaitEventSem( hevNetBiosLSN, SEM_INDEFINITE_WAIT ) ; } if ( pRecvNCB->basic_ncb.bncb.ncb_retcode == NB_COMMAND_IN_PROCESS ) NCBCancel( NetbeuiAPI, &CleanupNCB, NetBiosAdapter, pRecvNCB ) ; for ( i=0 ; ibasic_ncb.bncb.ncb_retcode == NB_COMMAND_IN_PROCESS ) NCBCancel( NetbeuiAPI, &CleanupNCB, NetBiosAdapter, pSendNCB[i] ) ; } NCBHangup( NetbeuiAPI, pWorkNCB, NetBiosAdapter, NetBiosLSN ) ; } NetBiosLSN = 0 ; strncpy( NetBiosRemote, " ", NETBIOS_NAME_LEN ) ; DosResetEventSem( hevNetBiosLSN, &PostCount ) ; ttyfd = -1 ; Dos16SemSet( pListenNCB->basic_ncb.ncb_semaphore ) ; } #endif /* CK_NETBIOS */ #ifdef NPIPE if ( nettype == NET_PIPE ) { if ( hPipe ) { rc = DosClose( hPipe ) ; hPipe = 0 ; ttyfd = -1 ; } return rc ; } #endif /* NPIPE */ #ifdef TCPSOCKET if ( nettype == NET_TCPB ) { if (!tcp_avail) return -1 ; return netclos(); } #endif /* TCPSOCKET */ #ifdef DECNET if ( nettype == NET_DEC ) { if (ttyfd > -1) { memset( &lcb, 0, sizeof(struct lat_cb) ) ; lcb.LatFunction = STOP_SESSION; lcb.SessionHandle = ttyfd; LATENTRY(&lcb); rc = (lcb.LatStatus == 0) ? 0 : -1; } } #endif /* DECNET */ ttyfd = -1; /* Mark it as closed. */ return(rc); } /* N E T T C H K -- Check if network up, and how many bytes can be read */ /* Returns number of bytes waiting, or -1 if connection has been dropped. */ int /* Check how many bytes are ready */ os2_nettchk() { /* for reading from network */ #ifdef NPIPE int rc = 0 ; ULONG bytesread ; AVAILDATA availdata ; ULONG PipeState ; #endif /* NPIPE */ #ifdef CK_NETBIOS if ( nettype == NET_BIOS ) { if ( NetBiosLSN > 0 ) { SESSIONINFO statusinfo ; if ( pos < size ) return size - pos ; #ifndef NONBTCHK /* This is for testing on a machine with LAN Distance installed when we want to run two CKs on the same machine without connecting to a remote network. NCBSessionStatus fails to return under these conditions. */ NCBSessionStatus( NetbeuiAPI, pWorkNCB, NetBiosAdapter, NetBiosName, &statusinfo, sizeof(SESSIONINFO), TRUE ) ; if ( pWorkNCB->basic_ncb.bncb.ncb_retcode == NB_COMMAND_SUCCESSFUL && statusinfo.session_state > NB_SESSION_STATE_SESSION_ACTIVE ) #endif /* NONBTCHK */ return 0 ; } return -1 ; } #endif /* CK_NETBIOS */ #ifdef NPIPE if ( nettype == NET_PIPE ) { char buffer[64]; if ( pos < size ) return size - pos ; if ( !(rc = DosPeekNPipe(hPipe, buffer, sizeof(buffer), &bytesread, &availdata, &PipeState)) ) { switch ( PipeState ) { case NP_STATE_DISCONNECTED: case NP_STATE_CLOSING: if ( PipeName[0] != PipeName[1] ) { /* Server Mode */ DosDisConnectNPipe( hPipe ) ; DosConnectNPipe( hPipe ) ; } else { /* Client Mode */ ttclos(0) ; } return -2 ; break; case NP_STATE_LISTENING: return 0 ; break; case NP_STATE_CONNECTED: return availdata.cbpipe ; break; default: return -1 ; } /* switch */ } else return (rc > 0 ? -rc : rc) ; } #endif /* NPIPE */ #ifdef TCPSOCKET if ( nettype == NET_TCPB ) { if (!tcp_avail) return -1 ; return nettchk(); } #endif /* TCPSOCKET */ #ifdef DECNET if ( nettype == NET_DEC ) { if ( pos < size ) { return size - pos ; } else { memset( &lcb, 0, sizeof(struct lat_cb) ) ; lcb.LatFunction = GET_STATUS ; lcb.SessionHandle = ttyfd; LATENTRY(&lcb); debug(F101,"os2_nettchk (DECNET) lcb.SessionStatus", "",lcb.SessionStatus) ; debug(F101,"os2_nettchk (DECNET) lcb.LatStatus","",lcb.LatStatus) ; return ( lcb.LatStatus & LS_RxData ) ? 1 : 0 ; } } #endif /* DECNET */ return(0); } /* N E T T I N C -- Input character from network */ int os2_netinc(timo) int timo; { int chr = -1; int rc = 0 ; time_t timer, timenow ; #ifdef CK_NETBIOS if ( nettype == NET_BIOS ) { if ( NetBiosLSN == -1 ) return -1 ; else if ( NetBiosLSN == 0 ) { if ( pListenNCB->basic_ncb.bncb.ncb_retcode != NB_COMMAND_IN_PROCESS ) { return -1 ; } else { rc = DosWaitEventSem( hevNetBiosLSN, timo > 0 ? timo * 1000 : timo < -1 ? 1000 : SEM_INDEFINITE_WAIT ) ; if (rc) return -1 ; } } if ( pos < size ) { chr = inbuf[pos++]; } else { rc = 0 ; if ( ( pRecvNCB->basic_ncb.bncb.ncb_retcode) == NB_COMMAND_IN_PROCESS) { rc = Dos16SemWait( pRecvNCB->basic_ncb.ncb_semaphore, timo > 0 ? timo * 1000 : timo < -1 ? 1000 : SEM_INDEFINITE_WAIT ) ; } if ( rc ) { return -1 ; } switch ( pRecvNCB->basic_ncb.bncb.ncb_retcode ) { case NB_COMMAND_SUCCESSFUL: if ( (size = pRecvNCB->basic_ncb.bncb.ncb_length) == 0 ) return -1 ; memcpy( inbuf, NetBiosRecvBuf, size ) ; rc = NCBReceive( NetbeuiAPI, pRecvNCB, NetBiosAdapter, NetBiosLSN, NetBiosRecvBuf, sizeof(NetBiosRecvBuf), FALSE ); break; case NB_SESSION_CLOSED: case NB_SESSION_ENDED_ABNORMALLY: ttclos(0) ; if ( ttname[0] == '*' ) { os2_netopen( "*",0,0 ) ; return -1 ; } else return -3 ; break; case NB_OS_ERROR_DETECTED: ttclos(0) ; return -3 ; break; case NB_COMMAND_IN_PROCESS: case NB_COMMAND_TIME_OUT: case NB_COMMAND_CANCELLED: default: return -1 ; } pos = 0 ; chr = inbuf[pos++] ; } return chr ; } #endif /* CK_NETBIOS */ #ifdef NPIPE if ( nettype == NET_PIPE ) { if ( timo < -1 ) timo = 1 ; /* Can't set timeout less than 1 sec */ if ( pos < size ) { chr = inbuf[pos++]; } else { if ( !timo ) { while ( !os2_nettchk() ) DosSleep(100) ; } else { timer = 0 ; while (1) { if ( os2_nettchk() ) break; if ( timo > 0 ) { if ( !timer ) timer = time(0) ; timenow = time(0) ; if ( timenow - timer > timo ) return -1 ; } DosSleep(100) ; } } rc = DosRead( hPipe, &inbuf, sizeof(inbuf), &size ) ; switch ( rc ) { case NO_ERROR: if ( !size ) return -1 ; break; case ERROR_BROKEN_PIPE: if ( PipeName[0] != PipeName[1] ) { /* Server Mode */ DosDisConnectNPipe( hPipe ) ; DosConnectNPipe( hPipe ) ; } else { /* Client Mode */ ttclos(0) ; } return -2 ; break; default: return -1 ; } pos = 0 ; chr = inbuf[pos++] ; } return chr ; } #endif /* NPIPE */ #ifdef TCPSOCKET if ( nettype == NET_TCPB ) { if (!tcp_avail) return -1 ; if ( (chr = netinc(timo)) != -1 ) return chr; else return (nettchk() == -1) ? -2 : -1; } #endif /* TCPSOCKET */ #ifdef DECNET if ( nettype == NET_DEC ) { if ( pos < size ) return inbuf[pos++]; memset( &lcb, 0, sizeof(struct lat_cb) ) ; memset( inbuf, 0, sizeof(inbuf) ) ; lcb.LatFunction = GET_CHAR_BLK; lcb.SessionHandle = ttyfd; lcb.BufferSize = sizeof(inbuf); lcb.BufferPtr = (void * _Seg16) inbuf; if ( timo < -1 ) lcb.WaitTime = 10L * -timo ; else if ( timo > 0 ) lcb.WaitTime = 1000L * timo ; else lcb.WaitTime = LAT_INDEFINITE_WAIT ; LATENTRY(&lcb); debug(F101,"os2_netinc (DECNET) lcb.SessionStatus","", lcb.SessionStatus) ; debug(F101,"os2_netinc (DECNET) lcb.LatStatus","",lcb.LatStatus) ; if ( (lcb.SessionStatus & 0xFF) == SS_Stopped ) return -2; if ( lcb.LatStatus ) { if ( lcb.LatStatus & LS_InvalidSize ) debug(F101,"os2_netinc (DECNET) LS_InvalidSize","", lcb.BufferSize) ; return -1 ; } pos = 0; size = lcb.BufferSize; debug(F111,"os2_netinc (DECNET) lcb.BufferSize",inbuf,lcb.BufferSize) ; chr = inbuf[pos++]; } #endif /* DECNET */ return chr; } #ifdef CK_NETBIOS static int NextSendNCB = 0 ; #endif /* CK_NETBIOS */ /* N E T T O C -- Output character to network */ /* Call with character to be transmitted. Returns 0 if transmission was successful, or -1 upon i/o error, or -2 if called improperly. */ int os2_nettoc(c) int c; { #ifdef DECNET int i; #endif /* DECNET */ int rc = -1; ULONG bytesWritten ; #ifdef CK_NETBIOS if ( nettype == NET_BIOS ) { int i = 0 ; int SendNCB ; UCHAR chr = c ; if ( NetBiosLSN == -1 ) return -1 ; else if ( NetBiosLSN == 0 ) { #ifdef COMMENT /* This code enables us to issue a blocking send prior to the establishment of a connection. The problem with this is that when a connection terminates and we are in Kermit Server mode, the Kermit Server will send a NAK in response to the timeout it received when the connection was lost. This NAK will be the first packet received by the next Client to complete a connection, and all packets in the exchange will be out of sequence. Therefore, we don't allow packets to be issued prior to the establishment of a real connection. */ if ( pListenNCB->basic_ncb.bncb.ncb_retcode != NB_COMMAND_IN_PROCESS ) { return -1 ; } else { rc = DosWaitEventSem( hevNetBiosLSN, SEM_INDEFINITE_WAIT ) ; if (rc) return -1 ; } #else if ( pListenNCB->basic_ncb.bncb.ncb_retcode != NB_COMMAND_SUCCESSFUL ) return -1 ; #endif /* COMMENT */ } for ( SendNCB = 0 ; SendNCB < MaxCmds ; SendNCB++ ) { if (pSendNCB[SendNCB]->basic_ncb.bncb.ncb_retcode != NB_COMMAND_IN_PROCESS ) break; } if ( SendNCB == MaxCmds ) return -1 ; if (pSendNCB[SendNCB]->basic_ncb.bncb.ncb_retcode == NB_COMMAND_IN_PROCESS) { NCB CancelNCB ; rc = NCBCancel( NetbeuiAPI, &CancelNCB, NetBiosAdapter, pSendNCB[SendNCB] ) ; Dos16SemWait( pSendNCB[SendNCB]->basic_ncb.ncb_semaphore, SEM_INDEFINITE_WAIT ) ; } memcpy( NetBiosSendBuf[SendNCB], &chr, sizeof(chr) ) ; rc = NCBSend( NetbeuiAPI, pSendNCB[SendNCB], NetBiosAdapter, NetBiosLSN, NetBiosSendBuf[SendNCB], sizeof(chr), FALSE ); #ifdef COMMENT /* Let's try a nonblocking Send */ Dos16SemWait( pSendNCB[SendNCB]->basic_ncb.ncb_semaphore, SEM_INDEFINITE_WAIT ) ; #endif /* COMMENT */ switch ( pSendNCB[SendNCB]->basic_ncb.bncb.ncb_retcode ) { case NB_COMMAND_SUCCESSFUL: case NB_COMMAND_IN_PROCESS: return 0 ; break; case NB_SESSION_CLOSED: case NB_SESSION_ENDED_ABNORMALLY: ttclos(0) ; if ( ttname[0] == '*' ) { os2_netopen( "*",0,0 ) ; return -1 ; } else return -2 ; break; case NB_OS_ERROR_DETECTED: ttclos(0) ; return -3 ; break; case NB_COMMAND_TIME_OUT: case NB_COMMAND_CANCELLED: default: return -1 ; } } #endif /* CK_NETBIOS */ #ifdef NPIPE if ( nettype == NET_PIPE ) { UCHAR chr = c ; rc = DosWrite( hPipe, &chr, sizeof(chr), &bytesWritten ) ; if ( rc ) return -1 ; else return 0 ; } #endif /* NPIPE */ #ifdef TCPSOCKET if ( nettype == NET_TCPB ) { if (!tcp_avail) return -1 ; return nettoc((char) c); } #endif /* TCPSOCKET */ #ifdef DECNET if ( nettype == NET_DEC ) { debug(F100,"os2_nettoc (DECNET) begin send char","",0); pos = size ; /* Send the character */ memset( &lcb, 0, sizeof(struct lat_cb) ) ; lcb.LatFunction = SEND_CHAR; lcb.SessionHandle = ttyfd; lcb.CharByte = c; LATENTRY(&lcb); debug(F101,"os2_nettoc (DECNET) lcb.SessionStatus","", lcb.SessionStatus) ; debug(F101,"os2_nettoc (DECNET) lcb.LatStatus","",lcb.LatStatus) ; for (i = 0; i < 10000 && ( lcb.LatStatus & LS_CharNotSent ); i++) { DosSleep(1); /* give up rest of current timeslice */ LATENTRY(&lcb) ; debug(F100,"os2_nettoc (DECNET) repeat char send","",0); debug(F101,"os2_nettoc (DECNET) lcb.SessionStatus", "",lcb.SessionStatus) ; debug(F101,"os2_nettoc (DECNET) lcb.LatStatus","",lcb.LatStatus) ; } debug(F100,"os2_nettoc (DECNET) end send char","",0); rc = (lcb.LatStatus == LS_NoError) ? 0 : -1; } #endif /* DECNET */ return rc; } /* N E T T O L -- Output a string of bytes to the network */ /* Call with s = pointer to string, n = length. Returns number of bytes actuall written on success, or -1 on i/o error, -2 if called improperly. */ int os2_nettol(s,n) char *s; int n; { int rc; #ifdef NPIPE ULONG bytesWritten ; #endif /* NPIPE */ #ifdef CK_NETBIOS int SendNCB ; if ( nettype == NET_BIOS ) { if ( NetBiosLSN == -1 ) return -3 ; else if ( NetBiosLSN == 0 ) { #ifdef COMMENT /* This code enables us to issue a blocking send prior to the establishment of a connection. The problem with this is that when a connection terminates and we are in Kermit Server mode, the Kermit Server will send a NAK in response to the timeout it received when the connection was lost. This NAK will be the first packet received by the next Client to complete a connection, and all packets in the exchange will be out of sequence. Therefore, we don't allow packets to be issued prior to the establishment of a real connection. */ if ( pListenNCB->basic_ncb.bncb.ncb_retcode != NB_COMMAND_IN_PROCESS ) { return -1 ; } else { rc = DosWaitEventSem( hevNetBiosLSN, SEM_INDEFINITE_WAIT ) ; if (rc) return -1 ; } #else if ( pListenNCB->basic_ncb.bncb.ncb_retcode != NB_COMMAND_SUCCESSFUL ) return -1 ; #endif /* COMMENT */ } for ( SendNCB = 0 ; SendNCB < MaxCmds ; SendNCB++ ) { if (pSendNCB[SendNCB]->basic_ncb.bncb.ncb_retcode != NB_COMMAND_IN_PROCESS ) break; } if ( SendNCB == MaxCmds ) return -1 ; if (pSendNCB[SendNCB]->basic_ncb.bncb.ncb_retcode == NB_COMMAND_IN_PROCESS) { NCB CancelNCB ; rc = NCBCancel( NetbeuiAPI, &CancelNCB, NetBiosAdapter, pSendNCB[SendNCB] ); Dos16SemWait( pSendNCB[SendNCB]->basic_ncb.ncb_semaphore, SEM_INDEFINITE_WAIT ) ; } memcpy( NetBiosSendBuf[SendNCB], s, n ) ; rc = NCBSend( NetbeuiAPI, pSendNCB[SendNCB], NetBiosAdapter, NetBiosLSN, NetBiosSendBuf[SendNCB], n, FALSE ) ; #ifdef COMMENT /* Lets try a non blocking Send */ Dos16SemWait( pSendNCB[SendNCB]->basic_ncb.ncb_semaphore, SEM_INDEFINITE_WAIT ) ; #endif /* COMMENT */ debug(F101,"NETTOL: SendNCB","",SendNCB ) ; debug(F101,"NETTOL: NCB_retcode","", pSendNCB[SendNCB]->basic_ncb.bncb.ncb_retcode ) ; switch ( pSendNCB[SendNCB]->basic_ncb.bncb.ncb_retcode ) { case NB_COMMAND_SUCCESSFUL: case NB_COMMAND_IN_PROCESS: return pSendNCB[SendNCB]->basic_ncb.bncb.ncb_length ; break; case NB_SESSION_CLOSED: case NB_SESSION_ENDED_ABNORMALLY: ttclos(0) ; if ( ttname[0] == '*' ) { os2_netopen( "*",0,0 ) ; return -1 ; } else return -2 ; break; case NB_OS_ERROR_DETECTED: ttclos(0) ; return -3 ; break; case NB_MAX_CMNDS_EXCEEDED: case NB_COMMAND_TIME_OUT: case NB_COMMAND_CANCELLED: default: return -1 ; } } #endif /* CK_NETBIOS */ #ifdef NPIPE if ( nettype == NET_PIPE ) { rc = DosWrite( hPipe, s, n, &bytesWritten ) ; return ( rc ? -1 : bytesWritten ) ; } #endif /* NPIPE */ #ifdef TCPSOCKET if ( nettype == NET_TCPB ) { if (!tcp_avail) return -1 ; return nettol(s, n); } #endif /* TCPSOCKET */ #ifdef DECNET if ( nettype == NET_DEC ) { for ( rc = 0; rc < n; rc++, s++ ) if ( os2_nettoc(*s) ) break; } #endif /* DECNET */ return(rc); } /* N E T F L U I -- Flush network input buffer */ int os2_netflui() { #ifdef CK_NETBIOS if ( nettype == NET_BIOS ) { pos = size ; return 0 ; } #endif /* CK_NETBIOS */ #ifdef NPIPE if ( nettype == NET_PIPE ) pos = size ; return 0 ; #endif /* NPIPE */ #ifdef TCPSOCKET if ( nettype == NET_TCPB ) { if (!tcp_avail) return 0 ; return netflui(); } #endif /* TCPSOCKET */ #ifdef DECNET if ( nettype == NET_DEC ) { pos = size ; return (0) ; } #endif /* DECNET */ return(0); } /* Send network BREAK */ /* Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully. */ int os2_netbreak() { int rc = -1; #ifdef CK_NETBIOS if ( nettype == NET_BIOS ) { return 0 ; } #endif /* CK_NETBIOS */ #ifdef NPIPE if ( nettype == NET_PIPE ) return 0 ; #endif /* NPIPE */ #ifdef TCPSOCKET if ( nettype == NET_TCPB ) { if (!tcp_avail) return -1 ; return netbreak(); } #endif /* TCPSOCKET */ #ifdef DECNET if ( nettype == NET_DEC ) { memset( &lcb, 0, sizeof(struct lat_cb) ) ; lcb.LatFunction = SEND_BREAK; lcb.SessionHandle = ttyfd; LATENTRY(&lcb); rc = (lcb.LatStatus == 0) ? 0 : -1; } #endif /* DECNET */ return rc; } /* * what follows is all dynamic link stuff to let the same executable * run on machines with and without networking software */ #ifdef __32BIT__ #define GetProc(h, n, e) DosQueryProcAddr(h, 0, n, (PFN *) e) #define PREFIX #else #define GetProc(h, n, e) DosGetProcAddr(h, n, (PFN *) e) #define PREFIX "_" #endif #ifdef TCPSOCKET int os2_tcpipinit() { char dll[_MAX_PATH], fail[_MAX_PATH]; HMODULE library; extern char startupdir[]; int rc=1 ; char * CKTCPIPDLL ; char *p, *q; p = q = strdup(startupdir); if (p) { while (*p) { if (*p == '/') *p = '\\'; if (islower(*p)) *p = toupper(*p); p++; } p = q; } else p = startupdir; tcp_avail = 0 ; if (deblog) { printf( " TCP/IP support..." ) ; debug(F100,"TCP/IP support...","",0); } tcpname[0] = NUL; /* User can override DLL search order with an environment variable */ CKTCPIPDLL = getenv( "CKTCPIPDLL" ) ; if ( CKTCPIPDLL ) { strcpy(dll, p); strcat(dll, CKTCPIPDLL ); rc = DosLoadModule(fail, sizeof(fail), dll, &library) ; if (!rc) { if (deblog) printf( "CKTCPIPDLL=%s loaded...",CKTCPIPDLL) ; sprintf(tcpname,"CKTCPIPDLL=%s",CKTCPIPDLL) ; debug(F111,"CKTCPIPDLL var loaded",CKTCPIPDLL,rc); } else debug(F111,"CKTCPIPDLL file not found",CKTCPIPDLL,rc); } else debug(F100,"CKTCPIPDLL not defined","",0); #ifdef __32BIT__ /* Attempt to load in the following order: 1. CKTCPIPDLL environment variable 2. IBM 2.0 3. FTP 1.3 4. IBM 1.2 */ if (rc != 0) { strcpy(dll, p); strcat(dll, "CKO32I20.DLL"); rc = DosLoadModule(fail, sizeof(fail), dll, &library) ; if (!rc) { if (deblog) printf( "32bit IBM 2.0 TCP/IP loaded...") ; sprintf(tcpname,"%s = 32-bit IBM TCP/IP 2.0", dll); debug(F111,"32bit IBM TCP/IP 2.0 loaded",dll,rc); } else debug(F111,"32bit IBM TCP/IP 2.0 load failed",dll,rc); } if (rc != 0) { strcpy(dll, p); strcat(dll, "CKO32F13.DLL"); rc = DosLoadModule(fail, sizeof(fail), dll, &library) ; if (!rc) { if (deblog) printf( "32bit FTP PC/TCP 1.3 loaded...") ; sprintf(tcpname,"%s = 32-bit FTP PC/TCP 1.3", dll); debug(F111,"32bit FTP PC/TCP 1.3 loaded",dll,rc); } else debug(F111,"32bit FTP PC/TCP 1.3 load failed",dll,rc); } if (rc != 0) { strcpy(dll, p); strcat(dll, "CKO32I12.DLL"); rc = DosLoadModule(fail, sizeof(fail), dll, &library) ; if (!rc) { HMODULE tcpiplib ; PFN pfn ; rc = DosLoadModule(fail, sizeof(fail), "TCPIPDLL", &tcpiplib) ; rc = GetProc(tcpiplib,"_bsdselect", &pfn); } if (!rc) { if (deblog) printf( "32bit IBM TCP/IP 1.2 (or compatible) loaded...") ; sprintf(tcpname,"%s = 32-bit IBM TCP/IP 1.2 (or compatible)", dll); debug(F111,"32bit IBM TCP/IP 1.2 (or compatible) loaded",dll,rc); } else debug(F111, "32bit IBM TCP/IP 1.2 (or compatible) load failed",dll,rc); } #else /* Attempt to load in the following order: 1. CKTCPIPDLL environment variable 2. FTP 1.3 3. IBM 1.2 */ if (rc != 0) { strcpy(dll, p); strcat(dll, "CKO16F13.DLL"); rc = DosLoadModule(fail, sizeof(fail), dll, &library) ; if (!rc) { if (deblog) printf( "16bit FTP PC/TCP 1.3 loaded...") ; sprintf(tcpname,"%s = 16-bit FTP PC/TCP 1.3", dll); debug(F111,"16bit FTP PC/TCP 1.3 loaded",dll,rc); } else debug(F111,"16bit FTP PC/TCP 1.3 load failed",dll,rc); } if (rc != 0) { strcpy(dll, p); strcat(dll, "CKO16I12.DLL"); rc = DosLoadModule(fail, sizeof(fail), dll, &library) ; if (!rc) { HMODULE tcpiplib ; PFN pfn ; rc = DosLoadModule(fail, sizeof(fail), "TCPIPDLL", &tcpiplib) ; rc = GetProc(tcpiplib,"_bsdselect", &pfn); } if (!rc) { if (deblog) printf( "16bit IBM TCP/IP 1.2 (or compatible) loaded...") ; sprintf(tcpname,"%s = 16-bit IBM TCP/IP 1.2", dll); debug(F111,"16bit IBM TCP/IP 1.2 (or compatible) loaded",dll,rc); } else debug(F111, "16bit IBM TCP/IP 1.2 (or compatible) load failed",dll,rc); } #endif /* __32BIT__ */ if (rc != 0) { if (deblog) { printf( "Not installed\n") ; debug(F101,"TCP/IP not installed - rc","",rc); } sprintf(tcpname,"(no TCP/IP DLL found)"); return -1; } if (GetProc(library, PREFIX "ck_sockinit", &sockinit) || GetProc(library, PREFIX "ck_connect", &connect) || GetProc(library, PREFIX "ck_ioctl", &ioctl) || GetProc(library, PREFIX "ck_recv", &recv) || GetProc(library, PREFIX "ck_select", &select) || GetProc(library, PREFIX "ck_send", &send) || GetProc(library, PREFIX "ck_setsockopt", &setsockopt) || GetProc(library, PREFIX "ck_socket", &socket) || GetProc(library, PREFIX "ck_soclose", &soclose) || GetProc(library, PREFIX "ck_gethostbyname", &gethostbyname) || GetProc(library, PREFIX "ck_getservbyname", &getservbyname) || GetProc(library, PREFIX "ck_inet_addr", &inet_addr) || GetProc(library, PREFIX "ck_inet_ntoa", &inet_ntoa)) { if (deblog) { printf( "Not installed\n") ; debug(F100,"TCP/IP not installed","",0); } strcat(tcpname," - ERROR: Missing Entry Points"); return -1; } if (rc = sockinit()) { tcp_avail = 0 ; if (deblog) { printf( "init failed\n" ) ; strcat(tcpname," - ERROR: Initialization Failed"); debug(F101,"TCP/IP sockinit() failed","",rc); } } else { tcp_avail = 1; if (deblog) { printf( "initialized\n" ) ; debug(F101,"TCP/IP sockinit() successful","",rc); } } return rc; } #endif /* TCPSOCKET */ void netinit() { extern int nettype; char fail[256]; HMODULE library; if (deblog) { printf( "Initializing Network Support:\n" ) ; debug(F100,"Initializing Network Support:","",0) ; } #ifdef CK_NETBIOS os2_netbiosinit() ; #endif /* CK_NETBIOS */ #ifdef DECNET if (deblog) { printf(" DECNet support..." ) ; debug(F100,"DECNet support...","",0); } if ( !DosLoadModule(fail, sizeof(fail), "LATCALLS", &library) ) { if ( !GetProc(library, "LATENTRY", &LATENTRY) ) { dnet_avail = 1; if (deblog) { printf("OK\n") ; debug(F100,"DECNet OK","",0); memset( &lcb, 0, sizeof(struct lat_cb) ) ; lcb.LatFunction = READ_LATINFO; lcb.BufferSize = sizeof(latinfo); lcb.BufferPtr = (void * _Seg16) &latinfo; LATENTRY(&lcb); debug(F101,"DECNet LatStatus","",lcb.LatStatus) ; if (!lcb.LatStatus) { debug(F101,"DECNet Major Version","",latinfo.vermjr) ; debug(F101,"DECNet Minor Version","",latinfo.vermir) ; debug(F101,"DECNet Max Sessions","",latinfo.NSessions) ; debug(F101,"DECNet Max Buffers per Session","", latinfo.NBuffers) ; debug(F101,"DECNet Max Services","",latinfo.NServices) ; } } } else { dnet_avail = 0 ; if (deblog) { printf("Not installed\n" ) ; debug(F100,"DECNet not installed","",0) ; } } } else { dnet_avail = 0 ; if (deblog) { printf("Not installed\n" ) ; debug(F100,"DECNet not installed","",0) ; } } #endif /* DECNET */ #ifdef TCPSOCKET os2_tcpipinit() ; #ifdef COMMENT /* this code should never have been added to this module */ /* it results in there being an override variable even when */ /* one has never been assigned by the user */ if (tn_term == NULL) { switch (tt_type) { case TT_VT52: tn_term = strdup("vt52"); break; case TT_VT100: tn_term = strdup("vt100"); break; case TT_VT102: tn_term = strdup("vt102"); break; case TT_VT220: tn_term = strdup("vt220"); break; case TT_ANSI: tn_term = strdup("ansi"); break; } } #endif /* COMMENT */ #endif /* TCPSOCKET */ if (tcp_avail) /* Set the default network type */ nettype = NET_TCPB; /* TCP/IP first */ else if (dnet_avail) /* Then DECnet */ nettype = NET_DEC; #ifdef COMMENT /* NetBios cannot be set as a default network type even though we would like to because it requires that a NetBiosName be specified. If the default is already in use, then we will not know what name to use. Not providing a name will leave Kermit in an unknown state (network type NetBios without any means for addressing this session.) Better never to allow it to be set as a default. All the code to implement it is shown below though just in case. */ else if (netbiosAvail) { /* Then NETBIOS */ NCB ncb ; APIRET rc ; int x,y ; nettype = NET_BIOS; strncpy(NetBiosName, (*myhost?myhost:"kermit"),NETBIOS_NAME_LEN); for (x = y; x < NETBIOS_NAME_LEN; x++) NetBiosName[x] = SP; NetBiosName[NETBIOS_NAME_LEN] = NUL; printf("Verifying \"%s\" is a unique NetBIOS node name ...\n", NetBiosName) ; rc = NCBAddName( NetbeuiAPI, &ncb, 0, NetBiosName ) ; if ( rc ) { printf( "?Sorry, \"%s\" is already in use by another NetBIOS node.\n", NetBiosName); for ( x=0; x < NETBIOS_NAME_LEN; x++) NetBiosName[x] = SP ; } } #endif /* COMMENT */ #ifdef NPIPE else { /* Otherwise Named Pipes, */ nettype = NET_PIPE; /* which is always there. */ strncpy(pipename,"kermit",PIPENAML); /* better set the pipename */ } #else else nettype = NET_NONE; #endif /* NPIPE */ } int netcleanup() { #ifdef CK_NETBIOS os2_netbioscleanup() ; #endif /* CK_NETBIOS */ } #ifdef CK_NETBIOS void NetbiosListenThread(void * pArgList) { APIRET rc = 0 ; rc = Dos16SemWait( pListenNCB->basic_ncb.ncb_semaphore, SEM_INDEFINITE_WAIT ) ; if ( rc || pListenNCB->basic_ncb.bncb.ncb_retcode != NB_COMMAND_SUCCESSFUL ) { os2_netclos() ; } else { ttyfd = NetBiosLSN = pListenNCB->basic_ncb.bncb.ncb_lsn ; strncpy( NetBiosRemote, pListenNCB->basic_ncb.bncb.ncb_callname, NETBIOS_NAME_LEN ) ; #ifdef COMMENT if ( pRecvNCB->basic_ncb.bncb.ncb_retcode == NB_COMMAND_IN_PROCESS ) { NCB CleanupNCB ; NCBCancel( NetbeuiAPI, &CleanupNCB, NetBiosAdapter, pRecvNCB ) ; Dos16SemWait( pRecvNCB->basic_ncb.ncb_semaphore, SEM_INDEFINITE_WAIT ) ; } #endif /* COMMENT */ NCBReceive( NetbeuiAPI, pRecvNCB, NetBiosAdapter, NetBiosLSN, NetBiosRecvBuf, sizeof(NetBiosRecvBuf), FALSE ) ; } DosPostEventSem( hevNetBiosLSN ) ; ListenThreadID = -1 ; } #endif /* CK_NETBIOS */ #endif /* NETCONN */