home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / pub / test / text / sredird.c < prev   
C/C++ Source or Header  |  2020-01-01  |  64KB  |  2,101 lines

  1. /*
  2.     sredird: RFC 2217 compliant serial port redirector
  3.     Version 1.1.8++, 06 November 2001
  4.     Copyright (C) 1999, 2000 InfoTecna di Cesana D. & C. s.n.c. 
  5.     Copyright (C) 2001  Trustees of Columbia University in the City of New York
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  20.  
  21.     To contact the autor:
  22.  
  23.       Denis Sbragion
  24.       InfoTecna
  25.       Tel, Fax: +39 039 2324054
  26.       URL: http://www.infotecna.it
  27.       E-Mail: d.sbragion@infotecna.it
  28.  
  29.       Jeffrey Altman
  30.       The Kermit Project
  31.       Columbia University
  32.       URL: http://www.kermit-project.org/
  33.       E-mail: jaltman@columbia.edu
  34.  
  35.     Current design issues:
  36.  
  37.       . does not properly check implement BREAK handling.  Need to figure
  38.         out how to turn a BREAK on and then off based upon receipt of 
  39.         COM-PORT Subnegotiations
  40.  
  41.       . does not properly use select to handle input, output and
  42.         errors on all devices.
  43.  
  44.       . Lack of login processing
  45.  
  46.       . Lack of Telnet START_TLS to protect the data stream
  47.  
  48.       . Lack of Telnet AUTHENTICATION
  49.  
  50.       . LineState processing is not implemented
  51.  
  52.       . The code probably won't compile on most versions of Unix due to the
  53.         highly platform dependent nature of the serial apis.
  54.  
  55.     Fixed:
  56.  
  57.       . Telnet DO ECHO should not be refused.  The modem handles the echoing
  58.         if necessary.
  59.  
  60.       . Cisco IOS returns 0 to the client when INBOUND flow control is SET but
  61.         not supported seperately from OUTBOUND.
  62.        
  63.       . Track the state of the telnet negotiations
  64.  
  65.       . Add support for BINARY mode translations
  66. */
  67.  
  68. /* Return NoError, which is 0, on success */
  69.  
  70. /* Standard library includes */
  71. #include <stdio.h>
  72. #include <stdlib.h>
  73. #include <string.h>
  74. #include <unistd.h>
  75. #include <errno.h>
  76. #include <time.h>
  77. #include <sys/time.h>
  78. #include <sys/times.h>
  79. #include <sys/types.h>
  80. #include <sys/ioctl.h>
  81. #include <signal.h>
  82. #include <fcntl.h>
  83. #include <syslog.h>
  84. #include <termios.h>
  85. #include <termio.h>
  86. #include <sys/socket.h>
  87. #include <netinet/in.h>
  88. #include <netinet/ip.h>
  89. #include <netinet/tcp.h>
  90.  
  91. /* Version id */
  92. #define SredirdVersionId "Version 1.1.8+, 02 November 2001"
  93.  
  94. /* Locking constants */
  95. #define LockOk 0
  96. #define Locked 1
  97. #define LockKo 2
  98.  
  99. /* Error conditions constants */
  100. #define NoError 0
  101. #define Error 1
  102. #define OpenError -1
  103.  
  104. /* Maximum length of temporary strings */
  105. #define TmpStrLen 255
  106.  
  107. /* Buffer size */
  108. #define BufferSize 2048
  109.  
  110. /* File mode and file length for HDB (ASCII) stile lock file */
  111. #define LockFileMode 0644
  112. #define HDBHeaderLen 11
  113.  
  114. /* Base Telnet protocol constants (STD 8) */
  115. #define TNSE ((unsigned char) 240)
  116. #define TNNOP ((unsigned char) 241)
  117. #define TNSB ((unsigned char) 250)
  118. #define TNWILL ((unsigned char) 251)
  119. #define TNWONT ((unsigned char) 252)
  120. #define TNDO ((unsigned char) 253)
  121. #define TNDONT ((unsigned char) 254)
  122. #define TNIAC ((unsigned char) 255)
  123.  
  124. /* Base Telnet protocol options constants (STD 27, STD 28, STD 29) */
  125. #define TN_TRANSMIT_BINARY ((unsigned char) 0)
  126. #define TN_ECHO ((unsigned char) 1)
  127. #define TN_SUPPRESS_GO_AHEAD ((unsigned char) 3)
  128.  
  129. /* Base Telnet Com Port Control (CPC) protocol constants (RFC 2217) */
  130. #define TNCOM_PORT_OPTION ((unsigned char) 44)
  131.  
  132. /* CPC Client to Access Server constants */
  133. #define TNCAS_SIGNATURE ((unsigned char) 0)
  134. #define TNCAS_SET_BAUDRATE ((unsigned char) 1)
  135. #define TNCAS_SET_DATASIZE ((unsigned char) 2)
  136. #define TNCAS_SET_PARITY ((unsigned char) 3)
  137. #define TNCAS_SET_STOPSIZE ((unsigned char) 4)
  138. #define TNCAS_SET_CONTROL ((unsigned char) 5)
  139. #define TNCAS_NOTIFY_LINESTATE ((unsigned char) 6)
  140. #define TNCAS_NOTIFY_MODEMSTATE ((unsigned char) 7)
  141. #define TNCAS_FLOWCONTROL_SUSPEND ((unsigned char) 8)
  142. #define TNCAS_FLOWCONTROL_RESUME ((unsigned char) 9)
  143. #define TNCAS_SET_LINESTATE_MASK ((unsigned char) 10)
  144. #define TNCAS_SET_MODEMSTATE_MASK ((unsigned char) 11)
  145. #define TNCAS_PURGE_DATA ((unsigned char) 12)
  146.  
  147. /* CPC Access Server to Client constants */
  148. #define TNASC_SIGNATURE ((unsigned char) 100)
  149. #define TNASC_SET_BAUDRATE ((unsigned char) 101)
  150. #define TNASC_SET_DATASIZE ((unsigned char) 102)
  151. #define TNASC_SET_PARITY ((unsigned char) 103)
  152. #define TNASC_SET_STOPSIZE ((unsigned char) 104)
  153. #define TNASC_SET_CONTROL ((unsigned char) 105)
  154. #define TNASC_NOTIFY_LINESTATE ((unsigned char) 106)
  155. #define TNASC_NOTIFY_MODEMSTATE ((unsigned char) 107)
  156. #define TNASC_FLOWCONTROL_SUSPEND ((unsigned char) 108)
  157. #define TNASC_FLOWCONTROL_RESUME ((unsigned char) 109)
  158. #define TNASC_SET_LINESTATE_MASK ((unsigned char) 110)
  159. #define TNASC_SET_MODEMSTATE_MASK ((unsigned char) 111)
  160. #define TNASC_PURGE_DATA ((unsigned char) 112)
  161.  
  162. /* Modem state effective change mask */
  163. #define ModemStateECMask ((unsigned char) 255)
  164.  
  165. #define LineStateECMask ((unsigned char) 255)
  166.  
  167. /* Default modem state polling in milliseconds (100 msec should be enough) */
  168. #define ModemStatePolling 100
  169.  
  170. /* Standard boolean definition */
  171. typedef enum { False, True } Boolean;
  172.  
  173. /* Buffer structure */
  174. typedef
  175.   struct
  176.     {
  177.       unsigned char Buffer[BufferSize];
  178.       unsigned int RdPos;
  179.       unsigned int WrPos;
  180.     }
  181.   BufferType;
  182.  
  183. /* Complete lock file pathname */
  184. static char * LockFileName;
  185.  
  186. /* Complete device file pathname */
  187. static char * DeviceName;
  188.  
  189. /* True when the device ha been opened */
  190. Boolean DeviceOpened = False;
  191.  
  192. /* Device file descriptor */
  193. int DeviceFd;
  194.  
  195. /* Com Port Control enabled flag */
  196. Boolean TCPCEnabled = False;
  197.  
  198. /* True after retrieving the initial settings from the serial port */
  199. Boolean InitPortRetrieved = False;
  200.  
  201. /* Initial serial port settings */
  202. struct termios InitialPortSettings;
  203.  
  204. /* Maximum log level to log in the system log */
  205. static int MaxLogLevel = LOG_DEBUG + 1;
  206.  
  207. /* Status enumeration for IAC escaping and interpretation */
  208. typedef enum { IACNormal, IACReceived, IACComReceiving } IACState;
  209.  
  210. /* Effective status for IAC escaping and interpretation */
  211. static IACState IACEscape = IACNormal;
  212.  
  213. /* Same as above during signature reception */
  214. static IACState IACSigEscape;
  215.  
  216. /* Current IAC command begin received */
  217. static unsigned char IACCommand[TmpStrLen];
  218.  
  219. /* Position of insertion into IACCommand[] */
  220. static size_t IACPos;
  221.  
  222. /* Modem state mask set by the client */
  223. static unsigned char ModemStateMask = ((unsigned char) 255);
  224.  
  225. /* Line state mask set by the client */
  226. static unsigned char LineStateMask = ((unsigned char) 0);
  227.  
  228. /* Current status of the line control lines */
  229. static unsigned char LineState = ((unsigned char) 0);
  230.  
  231. /* Current status of the modem control lines */
  232. static unsigned char ModemState = ((unsigned char) 0);
  233.  
  234. /* Break state flag */
  235. Boolean BreakSignaled = False;
  236.  
  237. /* Input flow control flag */
  238. Boolean InputFlow = True;
  239.  
  240. /* Telnet State Machine */
  241. static struct _tnstate {
  242.     int sent_will:1;
  243.     int sent_do:1;
  244.     int sent_wont:1;
  245.     int sent_dont:1;
  246.     int is_will:1;
  247.     int is_do:1;
  248. } tnstate[256];
  249.  
  250. /* Function prototypes */
  251.  
  252. /* initialize Telnet State Machine */
  253. void InitTelnetStateMachine(void);
  254.  
  255. /* Initialize a buffer for operation */
  256. void InitBuffer(BufferType * B);
  257.  
  258. /* Check if the buffer is empty */
  259. Boolean IsBufferEmpty(BufferType * B);
  260.  
  261. /* Check if the buffer is full */
  262. Boolean IsBufferFull(BufferType * B);
  263.  
  264. /* Add a byte to a buffer */
  265. void AddToBuffer(BufferType * B, unsigned char C);
  266.  
  267. /* Get a byte from a buffer */
  268. unsigned char GetFromBuffer(BufferType * B);
  269.  
  270. /* Generic log function with log level control. Uses the same log levels
  271. of the syslog(3) system call */
  272. void LogMsg(int LogLevel, char * Msg);
  273.  
  274. /* Try to lock the file given in LockFile as pid LockPid using the classical
  275.   HDB (ASCII) file locking scheme */
  276. int HDBLockFile(char * LockFile, pid_t LockPid);
  277.  
  278. /* Remove the lock file created with HDBLockFile */
  279. void HDBUnlockFile(char * LockFile, pid_t LockPid);
  280.  
  281. /* Function executed when the program exits */
  282. void ExitFunction(void);
  283.  
  284. /* Function called on many signals */
  285. void SignalFunction(int Act);
  286.   
  287. /* Function called on break signal */
  288. void BreakFunction(int Act);
  289.  
  290. /* Retrieves the port speed from PortFd */
  291. unsigned long int GetPortSpeed(int PortFd);
  292.  
  293. /* Retrieves the data size from PortFd */
  294. unsigned char GetPortDataSize(int PortFd);
  295.  
  296. /* Retrieves the parity settings from PortFd */
  297. unsigned char GetPortParity(int PortFd);
  298.  
  299. /* Retrieves the stop bits size from PortFd */
  300. unsigned char GetPortStopSize(int PortFd);
  301.   
  302. /* Retrieves the flow control status, including DTR and RTS status,
  303. from PortFd */
  304. unsigned char GetPortFlowControl(int PortFd, unsigned char Which);
  305.  
  306. /* Return the status of the modem control lines (DCD, CTS, DSR, RNG) */
  307. unsigned char GetModemState(int PortFd,unsigned char PMState);
  308.  
  309. /* Set the serial port data size */
  310. void SetPortDataSize(int PortFd, unsigned char DataSize);
  311.  
  312. /* Set the serial port parity */
  313. void SetPortParity(int PortFd, unsigned char Parity);
  314.  
  315. /* Set the serial port stop bits size */
  316. void SetPortStopSize(int PortFd, unsigned char StopSize);
  317.  
  318. /* Set the port flow control and DTR and RTS status */
  319. void SetPortFlowControl(int PortFd,unsigned char How);
  320.  
  321. /* Set the serial port speed */ 
  322. void SetPortSpeed(int PortFd, unsigned long BaudRate);
  323.  
  324. /* Send the signature Sig to the client */
  325. void SendSignature(BufferType *, char * Sig);
  326.  
  327. /* Write a char to SockFd performing IAC escaping */
  328. void EscWriteChar(BufferType *, unsigned char C);
  329.  
  330. /* Redirect char C to PortFd checking for IAC escape sequences */
  331. void EscRedirectChar(BufferType *, BufferType *, int PortFd, unsigned char C);
  332.  
  333. /* Send the specific telnet option to SockFd using Command as command */
  334. void SendTelnetOption(BufferType *, unsigned char Command, char Option);
  335.   
  336. /* Send a string to SockFd performing IAC escaping */
  337. void SendStr(BufferType *, char * Str);
  338.  
  339. /* Send the baud rate BR to SockFd */
  340. void SendBaudRate(BufferType *, unsigned long int BR);
  341.  
  342. /* Send the flow control command Command */
  343. void SendCPCFlowCommand(BufferType *, unsigned char Command);
  344.  
  345. /* Send the CPC command Command using Parm as parameter */
  346. void SendCPCByteCommand(BufferType *, unsigned char Command, unsigned char Parm);
  347.  
  348. /* Handling of COM Port Control specific commands */
  349. void HandleCPCCommand(BufferType *, int PortFd, unsigned char * Command, size_t CSize);
  350.  
  351. /* Common telnet IAC commands handling */
  352. void HandleIACCommand(BufferType *, int PortFd, unsigned char * Command, size_t CSize);
  353.  
  354. /* Write a buffer to SockFd with IAC escaping */
  355. void EscWriteBuffer(BufferType *, unsigned char * Buffer, unsigned int BSize);
  356.  
  357. /* initialize Telnet State Machine */
  358. void InitTelnetStateMachine(void)
  359. {
  360.     int i;
  361.     for ( i=0; i<256 ; i++ ) {
  362.         tnstate[i].sent_do = 0;
  363.         tnstate[i].sent_will = 0;
  364.         tnstate[i].sent_wont = 0;
  365.         tnstate[i].sent_dont = 0;
  366.         tnstate[i].is_do = 0;
  367.         tnstate[i].is_will = 0;
  368.     }
  369. }
  370.  
  371. /* Initialize a buffer for operation */
  372. void InitBuffer(BufferType * B)
  373.   {
  374.     /* Set the initial buffer positions */
  375.     B->RdPos = 0;
  376.     B->WrPos = 0;
  377.   }
  378.  
  379. /* Check if the buffer is empty */
  380. Boolean IsBufferEmpty(BufferType * B)
  381.   {
  382.     return((Boolean) B->RdPos == B->WrPos);
  383.   }
  384.  
  385. /* Check if the buffer is full */
  386. Boolean IsBufferFull(BufferType * B)
  387. {
  388.     /* We consider the buffer to be filled when there are 100 bytes left 
  389.      * This is so even a full buffer can safely have escaped characters 
  390.      * added to it.
  391.      */
  392.     return((Boolean) B->WrPos == (B->RdPos + BufferSize - 101) % BufferSize);
  393. }
  394.  
  395. /* Add a byte to a buffer */
  396. void AddToBuffer(BufferType * B, unsigned char C)
  397. {
  398.     B->Buffer[B->WrPos] = C;
  399.     B->WrPos = (B->WrPos + 1) % BufferSize;
  400. }
  401.  
  402. void PushToBuffer(BufferType * B, unsigned char C)
  403. {
  404.     B->RdPos = (B->RdPos == 0 ? BufferSize-1 : B->RdPos--);
  405.     B->Buffer[B->RdPos] = C;
  406. }
  407.  
  408. /* Get a byte from a buffer */
  409. unsigned char GetFromBuffer(BufferType * B)
  410.   {
  411.     unsigned char C = B->Buffer[B->RdPos];
  412.     B->RdPos = (B->RdPos + 1) % BufferSize;
  413.     return(C);
  414.   }
  415.   
  416. /* Generic log function with log level control. Uses the same log levels
  417.   of the syslog(3) system call */
  418. void LogMsg(int LogLevel, char * Msg)
  419.   {
  420.     if (LogLevel <= MaxLogLevel)
  421.       syslog(LogLevel,Msg);
  422.   }
  423.  
  424. /* Try to lock the file given in LockFile as pid LockPid using the classical
  425.   HDB (ASCII) file locking scheme */
  426. int HDBLockFile(char * LockFile, pid_t LockPid)
  427.   {
  428.     pid_t Pid;
  429.     int FileDes;
  430.     int N;
  431.     char HDBBuffer[HDBHeaderLen + 1];
  432.     char LogStr[TmpStrLen];
  433.  
  434.     /* Try to create the lock file */
  435.     while ((FileDes = open(LockFile,O_CREAT | O_WRONLY | O_EXCL,
  436.       LockFileMode)) == OpenError)
  437.       {
  438.         /* Check the kind of error */
  439.         if ((errno == EEXIST) && 
  440.           ((FileDes = open(LockFile,O_RDONLY,0)) != OpenError))
  441.           {
  442.             /* Read the HDB header from the existing lockfile */
  443.             N = read(FileDes,HDBBuffer,HDBHeaderLen);
  444.             close(FileDes);
  445.  
  446.             /* Check if the header has been read */
  447.             if (N <= 0)
  448.               {
  449.                 /* Emtpy lock file or error: may be another application
  450.                   was writing its pid in it */
  451.                 sprintf(LogStr,"Can't read pid from lock file %s",LockFile);
  452.                 LogMsg(LOG_NOTICE,LogStr);
  453.  
  454.                 /* Lock process failed */
  455.                 return(LockKo);
  456.               }
  457.  
  458.             /* Gets the pid of the locking process */
  459.             HDBBuffer[N] = '\0';
  460.             Pid = atoi(HDBBuffer);
  461.  
  462.             /* Check if it is our pid */
  463.             if (Pid == LockPid)
  464.               {
  465.                 /* File already locked by us */
  466.                 sprintf(LogStr,"Read our pid from lock %s",LockFile);
  467.                 LogMsg(LOG_DEBUG,LogStr);
  468.  
  469.                 /* Lock process succeded */
  470.                 return(LockOk);
  471.               }
  472.  
  473.             /* Check if hte HDB header is valid and if the locking process
  474.               is still alive */
  475.             if ((Pid == 0) || ((kill(Pid,0) != 0) && (errno == ESRCH)))
  476.               /* Invalid lock, remove it */
  477.               if (unlink(LockFile) == NoError)
  478.                 {
  479.                   sprintf(LogStr,"Removed stale lock %s (pid %d)",
  480.                     LockFile,Pid);
  481.                   LogMsg(LOG_NOTICE,LogStr);
  482.                 }
  483.               else
  484.                 {
  485.                   sprintf(LogStr,"Couldn't remove stale lock %s (pid %d)",
  486.                      LockFile,Pid);
  487.                   LogMsg(LOG_ERR,LogStr);
  488.                   return(LockKo);
  489.                 }
  490.             else
  491.               {
  492.                 /* The lock file is owned by another valid process */
  493.                 sprintf(LogStr,"Lock %s is owned by pid %d",LockFile,Pid);
  494.                 LogMsg(LOG_INFO,LogStr);
  495.  
  496.                 /* Lock process failed */
  497.                 return(Locked);
  498.               }
  499.           }
  500.         else
  501.           {
  502.             /* Lock file creation problem */
  503.             sprintf(LogStr,"Can't create lock file %s",LockFile);
  504.             LogMsg(LOG_ERR,LogStr);
  505.  
  506.             /* Lock process failed */
  507.             return(LockKo);
  508.           }
  509.       }
  510.  
  511.     /* Prepare the HDB buffer with our pid */
  512.     sprintf(HDBBuffer,"%10d\n",(int) LockPid);
  513.  
  514.     /* Fill the lock file with the HDB buffer */
  515.     if (write(FileDes,HDBBuffer,HDBHeaderLen) != HDBHeaderLen)
  516.       {
  517.         /* Lock file creation problem, remove it */
  518.         close(FileDes);
  519.         sprintf(LogStr,"Can't write HDB header to lock file %s",LockFile);
  520.         LogMsg(LOG_ERR,LogStr);
  521.         unlink(LockFile);
  522.         
  523.         /* Lock process failed */
  524.         return(LockKo);
  525.       }
  526.  
  527.     /* Closes the lock file */
  528.     close(FileDes);
  529.     
  530.     /* Lock process succeded */
  531.     return(LockOk);
  532.   }
  533.  
  534. /* Remove the lock file created with HDBLockFile */
  535. void HDBUnlockFile(char * LockFile, pid_t LockPid)
  536.   {
  537.     char LogStr[TmpStrLen];
  538.  
  539.     /* Check if the lock file is still owned by us */
  540.     if (HDBLockFile(LockFile,LockPid) == LockOk)
  541.       {
  542.         /* Remove the lock file */
  543.         unlink(LockFile);
  544.         sprintf(LogStr,"Unlocked lock file %s",LockFile);
  545.         LogMsg(LOG_NOTICE,LogStr);
  546.       }
  547.   }
  548.  
  549. /* Function executed when the program exits */
  550. void ExitFunction(void)
  551. {
  552.     /* Restores initial port settings */
  553.     if (InitPortRetrieved == True)
  554.       tcsetattr(DeviceFd,TCSANOW,&InitialPortSettings);
  555.  
  556.     /* Closes the device */
  557.     if (DeviceOpened == True)     
  558.       close(DeviceFd);
  559.  
  560.     /* Closes the sockets */
  561.     close(STDIN_FILENO);
  562.     close(STDOUT_FILENO);
  563.  
  564.     /* Removes the lock file */
  565.     HDBUnlockFile(LockFileName,getpid());
  566.  
  567.     /* Program termination notification */
  568.     LogMsg(LOG_NOTICE,"SRedird stopped");
  569.     
  570.     /* Closes the log */
  571.     closelog();
  572. }
  573.   
  574. /* Function called on many signals */
  575. void SignalFunction(int Act)
  576. {
  577.     /* Same as the exit function */
  578.     ExitFunction();
  579. }
  580.  
  581. /* Function called on break signal */
  582. void BreakFunction(int Act)
  583. {
  584. #ifndef COMMENT
  585.     /* Same as the exit function */
  586.     ExitFunction();
  587. #else /* COMMENT */
  588.     unsigned char LineState;
  589.  
  590.     if (BreakSignaled == True)        
  591.     {
  592.         BreakSignaled = False;      
  593.         LineState = 0;
  594.     }
  595.     else
  596.     {
  597.         BreakSignaled = True;
  598.         LineState = 16;
  599.     }
  600.  
  601.     /* Notify client of break change */
  602.     if ((LineStateMask & (unsigned char) 16) != 0)
  603.     {
  604.         LogMsg(LOG_DEBUG,"Notifying break change");
  605.         SendCPCByteCommand(&ToNetBuf,TNASC_NOTIFY_LINESTATE,LineState);
  606.     }
  607. #endif /* COMMENT */
  608. }
  609.  
  610. /* Retrieves the port speed from PortFd */
  611. unsigned long int GetPortSpeed(int PortFd)
  612.   {
  613.     struct termios PortSettings;
  614.     speed_t Speed;
  615.  
  616.     tcgetattr(PortFd,&PortSettings);
  617.     Speed = cfgetospeed(&PortSettings);
  618.  
  619.     switch (Speed)
  620.       {
  621.         case B50:
  622.           return(50UL);
  623.         case B75:
  624.           return(75UL);
  625.         case B110:
  626.           return(110UL);
  627.         case B134:
  628.           return(134UL);
  629.         case B150:
  630.           return(150UL);
  631.         case B200:
  632.           return(200UL);
  633.         case B300:
  634.           return(300UL);
  635.         case B600:
  636.           return(600UL);
  637.         case B1200:
  638.           return(1200UL);
  639.         case B1800:
  640.           return(1800UL);
  641.         case B2400:
  642.           return(2400UL);
  643.         case B4800:
  644.           return(4800UL);
  645.         case B9600:
  646.           return(9600UL);
  647.         case B19200:
  648.           return(19200UL);
  649.         case B38400:
  650.           return(38400UL);
  651.         case B57600:
  652.           return(57600UL);
  653.         case B115200:
  654.           return(115200UL);
  655.         case B230400:
  656.           return(230400UL);
  657.         case B460800:
  658.           return(460800UL);
  659.         default:
  660.           return(0UL);
  661.       }
  662.   }
  663.  
  664. /* Retrieves the data size from PortFd */
  665. unsigned char GetPortDataSize(int PortFd)
  666.   {
  667.     struct termios PortSettings;
  668.     tcflag_t DataSize;
  669.  
  670.     tcgetattr(PortFd,&PortSettings);
  671.     DataSize = PortSettings.c_cflag & CSIZE;
  672.  
  673.     switch (DataSize)
  674.       {
  675.         case CS5:
  676.           return((unsigned char) 5);
  677.         case CS6:
  678.           return((unsigned char) 6);
  679.         case CS7:
  680.           return((unsigned char) 7);
  681.         case CS8:
  682.           return((unsigned char) 8);
  683.         default:
  684.           return((unsigned char) 0);
  685.       }
  686.   }
  687.  
  688. /* Retrieves the parity settings from PortFd */
  689. unsigned char GetPortParity(int PortFd)
  690.   {
  691.     struct termios PortSettings;
  692.  
  693.     tcgetattr(PortFd,&PortSettings);
  694.  
  695.     if ((PortSettings.c_cflag & PARENB) == 0)
  696.       return((unsigned char) 1);
  697.  
  698.     if ((PortSettings.c_cflag & PARENB) != 0 &&
  699.       (PortSettings.c_cflag & PARODD) != 0)
  700.       return((unsigned char) 2);
  701.       
  702.     return((unsigned char) 3);
  703.   }
  704.  
  705. /* Retrieves the stop bits size from PortFd */
  706. unsigned char GetPortStopSize(int PortFd)
  707.   {
  708.     struct termios PortSettings;
  709.  
  710.     tcgetattr(PortFd,&PortSettings);
  711.  
  712.     if ((PortSettings.c_cflag & CSTOPB) == 0)
  713.       return((unsigned char) 1);
  714.     else
  715.       return((unsigned char) 2);
  716.   }
  717.   
  718. /* Retrieves the flow control status, including DTR and RTS status,
  719.   from PortFd */
  720. unsigned char GetPortFlowControl(int PortFd, unsigned char Which)
  721.   {
  722.     struct termios PortSettings;
  723.     int MLines;
  724.  
  725.     /* Gets the basic informations from the port */
  726.     tcgetattr(PortFd,&PortSettings);
  727.     ioctl(PortFd,TIOCMGET,&MLines);
  728.  
  729.     /* Check wich kind of information is requested */
  730.     switch (Which)
  731.       {
  732.         /* Com Port Flow Control Setting (outbound/both) */
  733.         case 0:
  734.           if (PortSettings.c_iflag & IXON)
  735.             return((unsigned char) 2);
  736.           if (PortSettings.c_cflag & CRTSCTS)
  737.             return((unsigned char) 3);
  738.           return((unsigned char) 0);
  739.         break;
  740.     
  741.         /* BREAK State  */
  742.         case 4:
  743.           if (BreakSignaled == True)
  744.             return((unsigned char) 5);
  745.           else
  746.             return((unsigned char) 6);
  747.         break;
  748.         
  749.         /* DTR Signal State */
  750.         case 7:
  751.           if (MLines & TIOCM_DTR)
  752.             return((unsigned char) 9);
  753.           else
  754.             return((unsigned char) 8);
  755.         break;
  756.  
  757.         /* RTS Signal State */
  758.         case 10:
  759.           if (MLines & TIOCM_RTS)
  760.             return((unsigned char) 12);
  761.           else
  762.             return((unsigned char) 11);
  763.         break;
  764.  
  765.         /* Com Port Flow Control Setting (inbound) */
  766.         case 13:
  767.           if (PortSettings.c_iflag & IXOFF)
  768.             return((unsigned char) 15);
  769.           if (PortSettings.c_cflag & CRTSCTS)
  770.             return((unsigned char) 16);
  771.           return((unsigned char) 14);
  772.         break;
  773.  
  774.         default:
  775.           if (PortSettings.c_iflag & IXON)
  776.             return((unsigned char) 2);
  777.           if (PortSettings.c_cflag & CRTSCTS)
  778.             return((unsigned char) 3);
  779.           return((unsigned char) 0);
  780.         break;
  781.       }
  782.   }
  783.  
  784. /* Return the status of the modem control lines (DCD, CTS, DSR, RNG) */
  785. unsigned char GetModemState(int PortFd,unsigned char PMState)
  786.   {
  787.     int MLines;
  788.     unsigned char MState = (unsigned char) 0;
  789.     
  790.     ioctl(PortFd,TIOCMGET,&MLines);
  791.  
  792.     if ((MLines & TIOCM_CAR) != 0)
  793.       MState += (unsigned char) 128;
  794.     if ((MLines & TIOCM_RNG) != 0)
  795.       MState += (unsigned char) 64;
  796.     if ((MLines & TIOCM_DSR) != 0)
  797.       MState += (unsigned char) 32;
  798.     if ((MLines & TIOCM_CTS) != 0)
  799.       MState += (unsigned char) 16;
  800.     if ((MState & 128) != (PMState & 128))
  801.       MState += (unsigned char) 8;
  802.     if ((MState & 64) != (PMState & 64))
  803.       MState += (unsigned char) 4;
  804.     if ((MState & 32) != (PMState & 32))
  805.       MState += (unsigned char) 2;
  806.     if ((MState & 16) != (PMState & 16))
  807.       MState += (unsigned char) 1;
  808.  
  809.     return(MState);
  810.   }
  811.  
  812. /* Set the serial port data size */
  813. void SetPortDataSize(int PortFd, unsigned char DataSize)
  814.   {
  815.     struct termios PortSettings;
  816.     tcflag_t PDataSize;
  817.  
  818.     switch (DataSize)
  819.       {
  820.         case 5:
  821.           PDataSize = CS5;
  822.         break;
  823.         case 6:
  824.           PDataSize = CS6;
  825.         break;
  826.         case 7:
  827.           PDataSize = CS7;
  828.         break;
  829.         case 8:
  830.           PDataSize = CS8;
  831.         break;
  832.         default:
  833.           PDataSize = CS8;
  834.         break;
  835.       }
  836.  
  837.     tcgetattr(PortFd,&PortSettings);
  838.     PortSettings.c_cflag = PortSettings.c_cflag &
  839.       ((PortSettings.c_cflag & ~CSIZE) | PDataSize);
  840.     tcsetattr(PortFd,TCSADRAIN,&PortSettings);
  841.   }
  842.  
  843. /* Set the serial port parity */
  844. void SetPortParity(int PortFd, unsigned char Parity)
  845.   {
  846.     struct termios PortSettings;
  847.  
  848.     tcgetattr(PortFd,&PortSettings);
  849.  
  850.     switch (Parity)
  851.       {
  852.         case 1:
  853.           PortSettings.c_cflag = PortSettings.c_cflag & ~PARENB;
  854.         break;
  855.         case 2:
  856.           PortSettings.c_cflag = PortSettings.c_cflag | PARENB | PARODD;
  857.         break;
  858.         case 3:
  859.           PortSettings.c_cflag = (PortSettings.c_cflag | PARENB) & ~PARODD;
  860.         break;
  861.         /* There's no support for MARK and SPACE parity so sets no parity */
  862.         default:
  863.           LogMsg(LOG_WARNING,"Requested unsupported parity. Set to no parity");
  864.           PortSettings.c_cflag = PortSettings.c_cflag & ~PARENB;
  865.         break;
  866.       }
  867.  
  868.     tcsetattr(PortFd,TCSADRAIN,&PortSettings);
  869.   }
  870.  
  871. /* Set the serial port stop bits size */
  872. void SetPortStopSize(int PortFd, unsigned char StopSize)
  873. {
  874.     struct termios PortSettings;
  875.  
  876.     tcgetattr(PortFd,&PortSettings);
  877.  
  878.     switch (StopSize)
  879.     {
  880.         case 1:
  881.           PortSettings.c_cflag = PortSettings.c_cflag & ~CSTOPB;
  882.         break;
  883.         case 2:
  884.           PortSettings.c_cflag = PortSettings.c_cflag | CSTOPB;
  885.         break;
  886.         case 3:
  887.           PortSettings.c_cflag = PortSettings.c_cflag & ~CSTOPB;
  888.           LogMsg(LOG_WARNING,"Requested unsupported 1.5 bits stop size. "
  889.             "Set to 1 bit stop size");
  890.         break;
  891.         default:
  892.           PortSettings.c_cflag = PortSettings.c_cflag & ~CSTOPB;
  893.         break;
  894.       }
  895.  
  896.     tcsetattr(PortFd,TCSADRAIN,&PortSettings);
  897. }
  898.  
  899. /* Set the port flow control and DTR and RTS status */
  900. void SetPortFlowControl(int PortFd,unsigned char How)
  901. {
  902.     struct termios PortSettings;
  903.     int MLines;
  904.  
  905.     /* Gets the base status from the port */
  906.     tcgetattr(PortFd,&PortSettings);
  907.     ioctl(PortFd,TIOCMGET,&MLines);
  908.  
  909.     /* Check which settings to change */
  910.     switch (How)
  911.     {
  912.         /* No Flow Control (outbound/both) */
  913.     case 1:
  914.         PortSettings.c_iflag = PortSettings.c_iflag & ~IXON;
  915.         PortSettings.c_iflag = PortSettings.c_iflag & ~IXOFF;
  916.         PortSettings.c_cflag = PortSettings.c_cflag & ~CRTSCTS;
  917.         break;
  918.         /* XON/XOFF Flow Control (outbound/both) */
  919.     case 2:
  920.         PortSettings.c_iflag = PortSettings.c_iflag | IXON;
  921.         PortSettings.c_iflag = PortSettings.c_iflag | IXOFF;
  922.         PortSettings.c_cflag = PortSettings.c_cflag & ~CRTSCTS;
  923.         break;
  924.         /* HARDWARE Flow Control (outbound/both) */
  925.     case 3:
  926.         PortSettings.c_iflag = PortSettings.c_iflag & ~IXON;
  927.         PortSettings.c_iflag = PortSettings.c_iflag & ~IXOFF;
  928.         PortSettings.c_cflag = PortSettings.c_cflag | CRTSCTS;
  929.         break;
  930.         /* BREAK State ON */
  931.     case 5:
  932.         tcsendbreak(PortFd,1);
  933.         BreakSignaled = True;
  934.         break;
  935.         /* BREAK State OFF */
  936.     case 6:
  937.         /* should not send another break */
  938.         /* tcsendbreak(PortFd,0); */
  939.         BreakSignaled = False;
  940.         break;
  941.         /* DTR Signal State ON */
  942.     case 8:
  943.         MLines = MLines | TIOCM_DTR;
  944.         break;
  945.         /* DTR Signal State OFF */
  946.     case 9:
  947.         MLines = MLines & ~TIOCM_DTR;
  948.         break;
  949.         /* RTS Signal State ON */
  950.     case 11:
  951.         MLines = MLines | TIOCM_RTS;
  952.         break;
  953.         /* RTS Signal State OFF */
  954.     case 12:
  955.         MLines = MLines & ~TIOCM_RTS;
  956.         break;
  957.  
  958.     /* INBOUND FLOW CONTROL is ignored */
  959.         /* No Flow Control (inbound) */
  960.     case 14:
  961.         /* XON/XOFF Flow Control (inbound) */
  962.     case 15:
  963.         /* HARDWARE Flow Control (inbound) */
  964.     case 16:
  965.         LogMsg(LOG_WARNING,"Inbound flow control ignored");
  966.         break;
  967.     default:
  968.         LogMsg(LOG_WARNING,"Requested unsupported flow control, "
  969.                 "setting to no flow control");
  970.         break;
  971.       }
  972.     
  973.     tcsetattr(PortFd,TCSADRAIN,&PortSettings);
  974.     ioctl(PortFd,TIOCMSET,&MLines);
  975. }
  976.  
  977. /* Set the serial port speed */ 
  978. void SetPortSpeed(int PortFd, unsigned long BaudRate)
  979.   {
  980.     struct termios PortSettings;
  981.     speed_t Speed;
  982.  
  983.     switch (BaudRate)
  984.       {
  985.         case 50UL:
  986.           Speed = B50;
  987.         break;
  988.         case 75UL:
  989.           Speed = B75;
  990.         break;
  991.         case 110UL:
  992.           Speed = B110;
  993.         break;
  994.         case 134UL:
  995.           Speed = B134;
  996.         break;
  997.         case 150UL:
  998.           Speed = B150;
  999.         break;
  1000.         case 200UL:
  1001.           Speed = B200;
  1002.         break;
  1003.         case 300UL:
  1004.           Speed = B300;
  1005.         break;
  1006.         case 600UL:
  1007.           Speed = B600;
  1008.         break;
  1009.         case 1200UL:
  1010.           Speed = B1200;
  1011.         break;
  1012.         case 1800UL:
  1013.           Speed = B1800;
  1014.         break;
  1015.         case 2400UL:
  1016.           Speed = B2400;
  1017.         break;
  1018.         case 4800UL:
  1019.           Speed = B4800;
  1020.         break;
  1021.         case 9600UL:
  1022.           Speed = B9600;
  1023.         break;
  1024.         case 19200UL:
  1025.           Speed = B19200;
  1026.         break;
  1027.         case 38400UL:
  1028.           Speed = B38400;
  1029.         break;
  1030.         case 57600UL:
  1031.           Speed = B57600;
  1032.         break;
  1033.         case 115200UL:
  1034.           Speed = B115200;
  1035.         break;
  1036.         case 230400UL:
  1037.           Speed = B230400;
  1038.         break;
  1039.         case 460800UL:
  1040.           Speed = B460800;
  1041.         break;
  1042.         default:
  1043.           LogMsg(LOG_WARNING,"Unknwon baud rate requested. Setting to 9600");
  1044.           Speed = B9600;
  1045.         break;
  1046.       }
  1047.       
  1048.     tcgetattr(PortFd,&PortSettings);
  1049.     cfsetospeed(&PortSettings,Speed);
  1050.     cfsetispeed(&PortSettings,Speed);
  1051.     tcsetattr(PortFd,TCSADRAIN,&PortSettings);
  1052.   }
  1053.   
  1054. /* Send the signature Sig to the client */
  1055. void SendSignature(BufferType * B, char * Sig)
  1056. {
  1057.     AddToBuffer(B,TNIAC);
  1058.     AddToBuffer(B,TNSB);
  1059.     AddToBuffer(B,TNCOM_PORT_OPTION);
  1060.     AddToBuffer(B,TNASC_SIGNATURE);
  1061.     SendStr(B,Sig);
  1062.     AddToBuffer(B,TNIAC);
  1063.     AddToBuffer(B,TNSE);
  1064. }
  1065.  
  1066. /* Write a char to socket performing IAC escaping */
  1067. void EscWriteChar(BufferType * B, unsigned char C)
  1068. {
  1069.     static unsigned char last=0;
  1070.  
  1071.     if (C == TNIAC)
  1072.         AddToBuffer(B,C);       
  1073.     else if (last == 0x0D && C != 0x0A && 
  1074.              !tnstate[TN_TRANSMIT_BINARY].is_will)
  1075.         AddToBuffer(B,0x00);
  1076.     AddToBuffer(B,C);
  1077.     last = C;
  1078. }
  1079.  
  1080. /* Redirect char C to Device checking for IAC escape sequences */
  1081. void EscRedirectChar(BufferType * SockB, BufferType * DevB, int PortFd, unsigned char C)
  1082. {
  1083.     static unsigned char last=0;
  1084.  
  1085.     /* Check the IAC escape status */
  1086.     switch (IACEscape)
  1087.     {
  1088.         /* Normal status */
  1089.     case IACNormal:
  1090.         if (C == TNIAC)
  1091.             IACEscape = IACReceived;
  1092.         else if (C == 0x00 && last == 0x0D && !tnstate[TN_TRANSMIT_BINARY].is_do)
  1093.             break;      /* swallow the NUL after a CR if not receiving BINARY */
  1094.         else 
  1095.             AddToBuffer(DevB,C);
  1096.         break;
  1097.  
  1098.         /* IAC previously received */
  1099.     case IACReceived:
  1100.         if (C == TNIAC)
  1101.         {
  1102.             AddToBuffer(DevB,C);
  1103.             IACEscape = IACNormal;
  1104.         }
  1105.         else
  1106.         {
  1107.             IACCommand[0] = TNIAC;
  1108.             IACCommand[1] = C;
  1109.             IACPos = 2;
  1110.             IACEscape = IACComReceiving;
  1111.             IACSigEscape = IACNormal;
  1112.         }
  1113.         break;
  1114.  
  1115.         /* IAC Command reception */
  1116.         case IACComReceiving:
  1117.         /* Telnet suboption, could be only CPC */
  1118.         if (IACCommand[1] == TNSB)
  1119.         {
  1120.             /* Get the suboption signature */
  1121.             if (IACPos < 4)
  1122.             {
  1123.                 IACCommand[IACPos] = C;
  1124.                 IACPos++;
  1125.             }
  1126.             else
  1127.             {
  1128.                 /* Check which suboption we are dealing with */
  1129.                 switch (IACCommand[3])
  1130.                 {
  1131.                     /* Signature, which needs further escaping */
  1132.                 case TNCAS_SIGNATURE:
  1133.                     switch (IACSigEscape)
  1134.                     {
  1135.                     case IACNormal:
  1136.                         if (C == TNIAC)
  1137.                             IACSigEscape = IACReceived;
  1138.                         else
  1139.                         {
  1140.                             if (IACPos < TmpStrLen)
  1141.                             {
  1142.                                 IACCommand[IACPos] = C;
  1143.                                 IACPos++;
  1144.                             }
  1145.                         }
  1146.                         break;
  1147.  
  1148.                     case IACComReceiving:
  1149.                         IACSigEscape = IACNormal;
  1150.                         break;
  1151.  
  1152.                     case IACReceived:
  1153.                         if (C == TNIAC)
  1154.                         {
  1155.                             if (IACPos < TmpStrLen)
  1156.                             {
  1157.                                 IACCommand[IACPos] = C;
  1158.                                 IACPos++;
  1159.                             }
  1160.                             IACSigEscape = IACNormal;
  1161.                         }
  1162.                         else
  1163.                         {
  1164.                             if (IACPos < TmpStrLen)
  1165.                             {
  1166.                                 IACCommand[IACPos] = TNIAC;
  1167.                                 IACPos++;
  1168.                             }
  1169.  
  1170.                             if (IACPos < TmpStrLen)
  1171.                             {
  1172.                                 IACCommand[IACPos] = C;
  1173.                                 IACPos++;
  1174.                             }
  1175.  
  1176.                             HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
  1177.                             IACEscape = IACNormal;
  1178.                         }
  1179.                         break;
  1180.                     }
  1181.                     break;
  1182.  
  1183.                     /* Set baudrate */
  1184.                 case TNCAS_SET_BAUDRATE:
  1185.                     IACCommand[IACPos] = C;
  1186.                     IACPos++;
  1187.  
  1188.                     if (IACPos == 10)
  1189.                     {
  1190.                         HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
  1191.                         IACEscape = IACNormal;
  1192.                     }
  1193.                     break;
  1194.  
  1195.                     /* Flow control command */
  1196.                 case TNCAS_FLOWCONTROL_SUSPEND:
  1197.                 case TNCAS_FLOWCONTROL_RESUME:
  1198.                     IACCommand[IACPos] = C;
  1199.                     IACPos++;
  1200.  
  1201.                     if (IACPos == 6)
  1202.                     {
  1203.                         HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
  1204.                         IACEscape = IACNormal;
  1205.                     }
  1206.                     break;
  1207.  
  1208.                     /* Normal CPC command with single byte parameter */
  1209.                 default:
  1210.                     IACCommand[IACPos] = C;
  1211.                     IACPos++;
  1212.  
  1213.                     if (IACPos == 7)
  1214.                     {
  1215.                         HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
  1216.                         IACEscape = IACNormal;
  1217.                     }
  1218.                     break;
  1219.                 }                                     
  1220.             }
  1221.         }         
  1222.         else    
  1223.         {
  1224.             /* Normal 3 byte IAC option */
  1225.             IACCommand[IACPos] = C;
  1226.             IACPos++;
  1227.  
  1228.             if (IACPos == 3)
  1229.             {
  1230.                 HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
  1231.                 IACEscape = IACNormal;
  1232.             }
  1233.         }
  1234.         break;
  1235.     }
  1236.     last = C;
  1237. }
  1238.  
  1239. /* Send the specific telnet option to SockFd using Command as command */
  1240. void SendTelnetOption(BufferType * B, unsigned char Command, char Option)
  1241. {
  1242.     unsigned char IAC = TNIAC;
  1243.  
  1244.     AddToBuffer(B,IAC);
  1245.     AddToBuffer(B,Command);
  1246.     AddToBuffer(B,Option);
  1247. }
  1248.  
  1249. /* Send a string to SockFd performing IAC escaping */
  1250. void SendStr(BufferType * B, char * Str)
  1251. {
  1252.     size_t I;
  1253.     size_t L;
  1254.  
  1255.     L = strlen(Str);
  1256.  
  1257.     for (I = 0; I < L;I++)
  1258.         EscWriteChar(B,(unsigned char) Str[I]);
  1259. }
  1260.  
  1261. /* Send the baud rate BR to Buffer */
  1262. void SendBaudRate(BufferType *B, unsigned long int BR)
  1263. {
  1264.     unsigned char C, *p;
  1265.     unsigned long int NBR;
  1266.     int i;
  1267.  
  1268.     NBR = htonl(BR);
  1269.  
  1270.     AddToBuffer(B,TNIAC);
  1271.     AddToBuffer(B,TNSB);
  1272.     AddToBuffer(B,TNCOM_PORT_OPTION);
  1273.     AddToBuffer(B,TNASC_SET_BAUDRATE);
  1274.     p = (char *)&NBR;
  1275.     for ( i=0;i<sizeof(NBR); i++)
  1276.         EscWriteChar(B,p[i]);
  1277.     AddToBuffer(B,TNIAC);
  1278.     AddToBuffer(B,TNSE);
  1279. }
  1280.  
  1281. /* Send the flow control command Command */
  1282. void SendCPCFlowCommand(BufferType *B, unsigned char Command)
  1283. {
  1284.     unsigned char C;
  1285.  
  1286.     AddToBuffer(B,TNIAC);
  1287.     AddToBuffer(B,TNSB);
  1288.     AddToBuffer(B,TNCOM_PORT_OPTION);
  1289.     AddToBuffer(B,Command);
  1290.     AddToBuffer(B,TNIAC);
  1291.     AddToBuffer(B,TNSE);
  1292.  
  1293.     if (Command == TNASC_FLOWCONTROL_SUSPEND)
  1294.       LogMsg(LOG_DEBUG,"Sent flow control suspend command");
  1295.     else
  1296.       LogMsg(LOG_DEBUG,"Sent flow control resume command");
  1297.     
  1298. }
  1299.   
  1300. /* Send the CPC command Command using Parm as parameter */
  1301. void SendCPCByteCommand(BufferType *B, unsigned char Command, unsigned char Parm)
  1302. {
  1303.     unsigned char C;
  1304.  
  1305.     AddToBuffer(B,TNIAC);
  1306.     AddToBuffer(B,TNSB);
  1307.     AddToBuffer(B,TNCOM_PORT_OPTION);
  1308.     AddToBuffer(B,Command);
  1309.     EscWriteChar(B,Parm);
  1310.     AddToBuffer(B,TNIAC);
  1311.     AddToBuffer(B,TNSE);
  1312. }
  1313.  
  1314. /* Handling of COM Port Control specific commands */
  1315. void HandleCPCCommand(BufferType *SockB, int PortFd, unsigned char * Command, size_t CSize)
  1316. {
  1317.     char LogStr[TmpStrLen];
  1318.     char SigStr[TmpStrLen];
  1319.     unsigned long int BaudRate;
  1320.     unsigned char DataSize;
  1321.     unsigned char Parity;
  1322.     unsigned char StopSize;
  1323.     unsigned char FlowControl;
  1324.     
  1325.     /* Check wich command has been requested */
  1326.     switch (Command[3])
  1327.     {
  1328.         /* Signature */
  1329.     case TNCAS_SIGNATURE:
  1330.         if (CSize == 6)
  1331.         {
  1332.             /* Void signature, client is asking for our signature */
  1333.             sprintf(SigStr,"SRedird %s",DeviceName);
  1334.             SendSignature(SockB,SigStr);
  1335.             sprintf(LogStr,"Sent signature: %s",SigStr);
  1336.             LogMsg(LOG_INFO,LogStr);
  1337.         }
  1338.         else
  1339.         {
  1340.             /* Received client signature */
  1341.             strncpy(SigStr,&Command[4],CSize - 6);
  1342.             sprintf(LogStr,"Received client signature: %s",SigStr);
  1343.             LogMsg(LOG_INFO,LogStr);
  1344.         }
  1345.         break;
  1346.  
  1347.         /* Set serial baud rate */
  1348.     case TNCAS_SET_BAUDRATE:
  1349.         /* Retrieve the baud rate which is in network order */
  1350.         BaudRate = ntohl(*((unsigned long int *) &Command[4]));
  1351.  
  1352.         if (BaudRate == 0)
  1353.         {
  1354.             /* Client is asking for current baud rate */
  1355.             LogMsg(LOG_DEBUG,"Baud rate notification received");              
  1356.         }
  1357.         else
  1358.         {
  1359.             /* Change the baud rate */
  1360.             sprintf(LogStr,"Port baud rate change to %lu requested",
  1361.                      BaudRate);
  1362.             LogMsg(LOG_DEBUG,LogStr);
  1363.             SetPortSpeed(PortFd,BaudRate);          
  1364.         }
  1365.  
  1366.         /* Send confirmation */
  1367.         BaudRate = GetPortSpeed(PortFd);
  1368.         SendBaudRate(SockB,BaudRate);
  1369.         sprintf(LogStr,"Port baud rate: %lu",BaudRate);
  1370.         LogMsg(LOG_DEBUG,LogStr);
  1371.         break;
  1372.         
  1373.         /* Set serial data size */
  1374.     case TNCAS_SET_DATASIZE:
  1375.         if (Command[4] == 0)
  1376.         {
  1377.             /* Client is asking for current data size */
  1378.             LogMsg(LOG_DEBUG,"Data size notification requested");             
  1379.         }
  1380.         else
  1381.         {
  1382.             /* Set the data size */
  1383.             sprintf(LogStr,"Port data size change to %u requested",
  1384.                      (unsigned int) Command[4]);
  1385.             LogMsg(LOG_DEBUG,LogStr);
  1386.             SetPortDataSize(PortFd,Command[4]);             
  1387.         }
  1388.  
  1389.         /* Send confirmation */
  1390.         DataSize = GetPortDataSize(PortFd);
  1391.         SendCPCByteCommand(SockB,TNASC_SET_DATASIZE,DataSize);
  1392.         sprintf(LogStr,"Port data size: %u",(unsigned int) DataSize);
  1393.         LogMsg(LOG_DEBUG,LogStr);
  1394.         break;
  1395.  
  1396.         /* Set the serial parity */
  1397.         case TNCAS_SET_PARITY:
  1398.         if (Command[4] == 0)
  1399.         {
  1400.             /* Client is asking for current parity */
  1401.             LogMsg(LOG_DEBUG,"Parity notification requested");            
  1402.         }
  1403.         else
  1404.         {
  1405.             /* Set the parity */
  1406.             sprintf(LogStr,"Port parity change to %u requested",
  1407.                      (unsigned int) Command[4]);
  1408.             LogMsg(LOG_DEBUG,LogStr);
  1409.             SetPortParity(PortFd,Command[4]);             
  1410.         }
  1411.  
  1412.         /* Send confirmation */
  1413.         Parity = GetPortParity(PortFd);
  1414.         SendCPCByteCommand(SockB,TNASC_SET_PARITY,Parity);
  1415.         sprintf(LogStr,"Port parity: %u",(unsigned int) Parity);
  1416.         LogMsg(LOG_DEBUG,LogStr);
  1417.         break;
  1418.         
  1419.         /* Set the serial stop size */
  1420.     case TNCAS_SET_STOPSIZE:
  1421.         if (Command[4] == 0)
  1422.         {
  1423.             /* Client is asking for current stop size */
  1424.             LogMsg(LOG_DEBUG,"Stop size notification requested");             
  1425.         }
  1426.         else
  1427.         {
  1428.             /* Set the stop size */
  1429.             sprintf(LogStr,"Port stop size change to %u requested",
  1430.                      (unsigned int) Command[4]);
  1431.             LogMsg(LOG_DEBUG,LogStr);
  1432.             SetPortStopSize(PortFd,Command[4]);
  1433.         }
  1434.  
  1435.         /* Send confirmation */
  1436.         StopSize = GetPortStopSize(PortFd);
  1437.         SendCPCByteCommand(SockB,TNASC_SET_STOPSIZE,StopSize);
  1438.         sprintf(LogStr,"Port stop size: %u",(unsigned int) StopSize);
  1439.         LogMsg(LOG_DEBUG,LogStr);
  1440.         break;
  1441.  
  1442.         /* Flow control and DTR/RTS handling */
  1443.     case TNCAS_SET_CONTROL:
  1444.         if (Command[4] == 0 || Command[4] == 4 || Command[4] == 7 ||
  1445.              Command[4] == 10 || Command[4] == 13)
  1446.         {   
  1447.             /* Client is asking for current flow control or DTR/RTS status */
  1448.             LogMsg(LOG_DEBUG,"Flow control notification requested");
  1449.             FlowControl = GetPortFlowControl(PortFd,Command[4]);
  1450.             SendCPCByteCommand(SockB,TNASC_SET_CONTROL,FlowControl);
  1451.             sprintf(LogStr,"Port flow control: %u",
  1452.                      (unsigned int) FlowControl);
  1453.             LogMsg(LOG_DEBUG,LogStr);
  1454.         }
  1455.         else if (Command[4] == 5)
  1456.         {
  1457.             /* Break command */
  1458.             tcsendbreak(PortFd,1);
  1459.             BreakSignaled = True;
  1460.             LogMsg(LOG_DEBUG,"Break Signal ON");
  1461.             SendCPCByteCommand(SockB,TNASC_SET_CONTROL,Command[4]);
  1462.         } else if (Command[4] == 6) {
  1463.             BreakSignaled = False;
  1464.             LogMsg(LOG_DEBUG,"Break Signal OFF");
  1465.             SendCPCByteCommand(SockB,TNASC_SET_CONTROL,Command[4]);
  1466.         } else {
  1467.             /* Set the flow control */
  1468.             sprintf(LogStr,"Port flow control change to %u requested",
  1469.                      (unsigned int) Command[4]);
  1470.             LogMsg(LOG_DEBUG,LogStr);
  1471.             SetPortFlowControl(PortFd,Command[4]);
  1472.  
  1473.             /* Flow control status confirmation */
  1474.             if (Command[4] >= 13 && Command[4] <=16)
  1475.                 /* INBOUND not supported separately.  
  1476.                  * Following the behavior of Cisco ISO 11.3
  1477.                  */
  1478.                 FlowControl = 0;
  1479.             else {
  1480.                 FlowControl = GetPortFlowControl(PortFd,0);
  1481.             }
  1482.             SendCPCByteCommand(SockB,TNASC_SET_CONTROL,FlowControl);
  1483.             sprintf(LogStr,"Port flow control: %u",
  1484.                      (unsigned int) FlowControl);
  1485.             LogMsg(LOG_DEBUG,LogStr);
  1486.         }
  1487.         break;
  1488.         
  1489.         /* Set the line state mask */
  1490.     case TNCAS_SET_LINESTATE_MASK:          
  1491.         sprintf(LogStr,"Line state set to %u",(unsigned int) Command[4]);
  1492.         LogMsg(LOG_DEBUG,LogStr);
  1493.         /* Only break notification supported */
  1494.         LineStateMask = Command[4] & (unsigned char) 16;
  1495.         SendCPCByteCommand(SockB,TNASC_SET_LINESTATE_MASK,LineStateMask);
  1496.         break;
  1497.  
  1498.         /* Set the modem state mask */
  1499.     case TNCAS_SET_MODEMSTATE_MASK:
  1500.         sprintf(LogStr,"Modem state mask set to %u",
  1501.                  (unsigned int) Command[4]);
  1502.         LogMsg(LOG_DEBUG,LogStr);
  1503.         ModemStateMask = Command[4];
  1504.         SendCPCByteCommand(SockB,TNASC_SET_MODEMSTATE_MASK,ModemStateMask);
  1505.         break;
  1506.  
  1507.         /* Port flush requested */
  1508.     case TNCAS_PURGE_DATA:
  1509.         sprintf(LogStr,"Port flush %u requested",(unsigned int) Command[4]);
  1510.         LogMsg(LOG_DEBUG,LogStr);
  1511.         switch (Command[4])
  1512.         {
  1513.             /* Inbound flush */
  1514.         case 1:
  1515.             tcflush(PortFd,TCIFLUSH);
  1516.             break;
  1517.             /* Outbound flush */
  1518.         case 2:
  1519.             tcflush(PortFd,TCOFLUSH);
  1520.             break;
  1521.             /* Inbound/outbound flush */
  1522.         case 3:
  1523.             tcflush(PortFd,TCIOFLUSH);
  1524.             break;
  1525.         }
  1526.  
  1527.         SendCPCByteCommand(SockB,TNASC_PURGE_DATA,Command[4]);
  1528.         break;
  1529.  
  1530.         /* Suspend output to the client */
  1531.     case TNCAS_FLOWCONTROL_SUSPEND:
  1532.         LogMsg(LOG_DEBUG,"Flow control suspend requested");
  1533.         InputFlow = False;
  1534.         break;
  1535.         
  1536.         /* Resume output to the client */
  1537.     case TNCAS_FLOWCONTROL_RESUME:
  1538.         LogMsg(LOG_DEBUG,"Flow control resume requested");
  1539.         InputFlow = True;
  1540.         break;
  1541.  
  1542.         /* Unknown request */
  1543.     default:
  1544.         sprintf(LogStr,"Unhandled request %u",(unsigned int) Command[3]);
  1545.         LogMsg(LOG_DEBUG,LogStr);
  1546.         break;
  1547.     } 
  1548. }     
  1549.  
  1550. /* Common telnet IAC commands handling */
  1551. void HandleIACCommand(BufferType * SockB, int PortFd, unsigned char * Command, size_t CSize)
  1552. {
  1553.     char LogStr[TmpStrLen];
  1554.      
  1555.     /* Check which command */
  1556.     switch(Command[1])
  1557.     {
  1558.         /* Suboptions */
  1559.     case TNSB:
  1560.         if (!(tnstate[Command[2]].is_will || tnstate[Command[2]].is_do))
  1561.             break;
  1562.  
  1563.         switch (Command[2])
  1564.         {
  1565.             /* RFC 2217 COM Port Control Protocol option */
  1566.         case TNCOM_PORT_OPTION:
  1567.             HandleCPCCommand(SockB,PortFd,Command,CSize);
  1568.             break;
  1569.               
  1570.         default:
  1571.             sprintf(LogStr,"Unknown suboption received: %u",
  1572.                      (unsigned int) Command[2]);
  1573.             LogMsg(LOG_DEBUG,LogStr);
  1574.             break;
  1575.         }
  1576.         break;
  1577.  
  1578.         /* Requests for options */
  1579.     case TNWILL:
  1580.         switch (Command[2])
  1581.         {
  1582.             /* COM Port Control Option */
  1583.         case TNCOM_PORT_OPTION:
  1584.             LogMsg(LOG_INFO,"Telnet COM Port Control Enabled (WILL)");
  1585.             TCPCEnabled = True;               
  1586.             if ( !tnstate[Command[2]].sent_do ) {
  1587.                 SendTelnetOption(SockB,TNDO,Command[2]);
  1588.             }
  1589.             tnstate[Command[2]].is_do = 1;
  1590.             break;
  1591.  
  1592.             /* Telnet Binary mode */
  1593.         case TN_TRANSMIT_BINARY:
  1594.             LogMsg(LOG_INFO,"Telnet Binary Transfer Enabled (WILL)");
  1595.             if ( !tnstate[Command[2]].sent_do ) {
  1596.                 SendTelnetOption(SockB,TNDO,Command[2]);
  1597.             }
  1598.             tnstate[Command[2]].is_do = 1;
  1599.             break;
  1600.  
  1601.             /* Echo request not handled */
  1602.         case TN_ECHO:
  1603.             LogMsg(LOG_INFO,"Rejecting Telnet Echo Option (WILL)");
  1604.             if ( !tnstate[Command[2]].sent_do ) {
  1605.                 SendTelnetOption(SockB,TNDO,Command[2]);
  1606.             }
  1607.             tnstate[Command[2]].is_do = 1;
  1608.             break;
  1609.  
  1610.             /* No go ahead needed */
  1611.         case TN_SUPPRESS_GO_AHEAD:
  1612.             LogMsg(LOG_INFO,"Suppressing Go Ahead characters (WILL)");
  1613.             if ( !tnstate[Command[2]].sent_do ) {
  1614.                 SendTelnetOption(SockB,TNDO,Command[2]);
  1615.             }
  1616.             tnstate[Command[2]].is_do = 1;
  1617.             break;
  1618.  
  1619.             /* Reject everything else */
  1620.         default:
  1621.             sprintf(LogStr,"Rejecting option WILL: %u",
  1622.                      (unsigned int) Command[2]);
  1623.             LogMsg(LOG_DEBUG,LogStr);
  1624.             SendTelnetOption(SockB,TNDONT,Command[2]);
  1625.             tnstate[Command[2]].is_do = 0;
  1626.             break;
  1627.         }
  1628.         tnstate[Command[2]].sent_do = 0;
  1629.         tnstate[Command[2]].sent_dont = 0;
  1630.         break;
  1631.  
  1632.         /* Confirmations for options */
  1633.     case TNDO:
  1634.         switch (Command[2])
  1635.         {
  1636.             /* COM Port Control Option */
  1637.         case TNCOM_PORT_OPTION:
  1638.             LogMsg(LOG_INFO,"Telnet COM Port Control Enabled (DO)");
  1639.             TCPCEnabled = True;               
  1640.             if ( !tnstate[Command[2]].sent_will ) {
  1641.                 SendTelnetOption(SockB,TNWILL,Command[2]);
  1642.             }
  1643.             tnstate[Command[2]].is_will = 1;
  1644.             break;
  1645.  
  1646.             /* Telnet Binary mode */
  1647.         case TN_TRANSMIT_BINARY:
  1648.             LogMsg(LOG_INFO,"Telnet Binary Transfer Enabled (DO)");
  1649.             if ( !tnstate[Command[2]].sent_will ) {
  1650.                 SendTelnetOption(SockB,TNWILL,Command[2]);
  1651.             }
  1652.             tnstate[Command[2]].is_will = 1;
  1653.             break;
  1654.  
  1655.             /* Echo request handled.  The modem will echo for the user. */
  1656.         case TN_ECHO:
  1657.             LogMsg(LOG_INFO,"Rejecting Telnet Echo Option (DO)");
  1658.             if ( !tnstate[Command[2]].sent_will ) {
  1659.                 SendTelnetOption(SockB,TNWILL,Command[2]);
  1660.             }
  1661.             tnstate[Command[2]].is_will = 1;
  1662.             break;
  1663.  
  1664.             /* No go ahead needed */
  1665.         case TN_SUPPRESS_GO_AHEAD:
  1666.             LogMsg(LOG_INFO,"Suppressing Go Ahead characters (DO)");
  1667.             if ( !tnstate[Command[2]].sent_will ) {
  1668.                 SendTelnetOption(SockB,TNWILL,Command[2]);
  1669.             }
  1670.             tnstate[Command[2]].is_will = 1;
  1671.             break;
  1672.  
  1673.             /* Reject everything else */
  1674.         default:
  1675.             sprintf(LogStr,"Rejecting option DO: %u",
  1676.                      (unsigned int) Command[2]);
  1677.             LogMsg(LOG_DEBUG,LogStr);
  1678.             SendTelnetOption(SockB,TNWONT,Command[2]);
  1679.             tnstate[Command[2]].is_will = 0;
  1680.             break;
  1681.         }
  1682.         tnstate[Command[2]].sent_will = 0;
  1683.         tnstate[Command[2]].sent_wont = 0;
  1684.         break;
  1685.         
  1686.         /* Notifications of rejections for options */
  1687.     case TNDONT:
  1688.         sprintf(LogStr,"Received rejection for option: %u",
  1689.                  (unsigned int) Command[2]);
  1690.         LogMsg(LOG_DEBUG,LogStr);
  1691.         if ( tnstate[Command[2]].is_will ) {
  1692.             SendTelnetOption(SockB,TNWONT,Command[2]);
  1693.             tnstate[Command[2]].is_will = 0;
  1694.         }
  1695.         tnstate[Command[2]].sent_will = 0;
  1696.         tnstate[Command[2]].sent_wont = 0;
  1697.         break;
  1698.  
  1699.     case TNWONT:
  1700.         if (Command[2] == TNCOM_PORT_OPTION)
  1701.         {
  1702.             LogMsg(LOG_ERR,"Client doesn't support Telnet COM Port "
  1703.                       "Protocol Option (RFC 2217), trying to serve anyway");
  1704.         }
  1705.         else
  1706.         {
  1707.             sprintf(LogStr,"Received rejection for option: %u",
  1708.                      (unsigned int) Command[2]);
  1709.             LogMsg(LOG_DEBUG,LogStr);
  1710.         }
  1711.         if ( tnstate[Command[2]].is_do ) {
  1712.             SendTelnetOption(SockB,TNDONT,Command[2]);
  1713.             tnstate[Command[2]].is_do = 0;
  1714.         }
  1715.         tnstate[Command[2]].sent_do = 0;
  1716.         tnstate[Command[2]].sent_dont = 0;
  1717.         break;
  1718.     }
  1719. }
  1720.  
  1721. /* Write a buffer to SockFd with IAC escaping */
  1722. void EscWriteBuffer(BufferType * B, unsigned char * Buffer, unsigned int BSize)
  1723. {
  1724.     unsigned int I;
  1725.  
  1726.     if (BSize > 0)
  1727.     {
  1728.         for (I = 0;I < BSize;I++) {
  1729.             if (Buffer[I] == TNIAC)
  1730.                 AddToBuffer(B,TNIAC);
  1731.             AddToBuffer(B,Buffer[I]);
  1732.         }
  1733.     }
  1734. }
  1735.  
  1736. /* Main function */
  1737. int main(int argc, char * argv[])
  1738. {   
  1739.     /* Input fd set */
  1740.     fd_set InFdSet;
  1741.     
  1742.     /* Output fd set */
  1743.     fd_set OutFdSet;
  1744.  
  1745.     /* Char read */
  1746.     unsigned char C;
  1747.  
  1748.     /* Temporary string for logging */
  1749.     char LogStr[TmpStrLen];
  1750.  
  1751.     /* Actual port settings */
  1752.     struct termios PortSettings;
  1753.  
  1754.     /* Base timeout for stream reading */
  1755.     struct timeval BTimeout;
  1756.  
  1757.     /* Timeout for stream reading */
  1758.     struct timeval RTimeout;
  1759.  
  1760.     /* Pointer to timeout structure to set */
  1761.     struct timeval * ETimeout = &RTimeout;
  1762.  
  1763.     /* Remote flow control flag */
  1764.     Boolean RemoteFlowOff = False;
  1765.  
  1766.     /* Buffer to Device from Network */
  1767.     BufferType ToDevBuf;
  1768.  
  1769.     /* Buffer to Network from Device */
  1770.     BufferType ToNetBuf;
  1771.  
  1772.     /* Socket setup flag */
  1773.     int SockParmEnable = 1;
  1774.     
  1775.     /* Generic socket parameter */
  1776.     int SockParm;
  1777.  
  1778.     /* Out buffer ticks count */
  1779.     clock_t OutBTicks = times(NULL);
  1780.  
  1781.     /* Out buffer clock ticks limit */
  1782.     clock_t MaxBTicks;
  1783.  
  1784.     /* Open the system log */
  1785.     openlog("sredird",LOG_PID,LOG_USER);
  1786.  
  1787.     /* Check the command line argument count */
  1788.     if (argc < 4)
  1789.       {
  1790.         /* Write little usage information */
  1791.         puts("sredird: RFC 2217 compliant serial port redirector");
  1792.         puts(SredirdVersionId);
  1793.         puts("This program should be run only by the inetd superserver");
  1794.         puts("Usage: sredird <loglevel> <device> <lockfile> [pollingterval]");
  1795.         puts("Poll interval is in milliseconds, default is 100, "
  1796.           "0 means no polling");
  1797.  
  1798.         /* Same on the system log */
  1799.         LogMsg(LOG_ERR,"sredird: RFC 2217 compliant serial port redirector");
  1800.         LogMsg(LOG_ERR,SredirdVersionId);
  1801.         LogMsg(LOG_ERR,"This program should be run only by the inetd "
  1802.           "superserver");
  1803.         LogMsg(LOG_ERR,"Usage: sredird <loglevel> <device> <lockfile> [pollingterval]");
  1804.         LogMsg(LOG_ERR,"Poll interval is in milliseconds, default is 100, "
  1805.           "0 means no polling");
  1806.  
  1807.         return(Error);
  1808.       }
  1809.  
  1810.     /* Sets the log level */
  1811.     MaxLogLevel = atoi(argv[1]);
  1812.  
  1813.     /* Retrieve the polling interval */
  1814.     if (argc == 5)
  1815.       {
  1816.         BTimeout.tv_sec = 0;
  1817.         BTimeout.tv_usec = atol(argv[4]) * 1000;
  1818.         MaxBTicks = (BTimeout.tv_usec * CLOCKS_PER_SEC) / (1000 * 1000);
  1819.  
  1820.         if (BTimeout.tv_usec <= 0)
  1821.           {
  1822.             ETimeout = NULL;
  1823.             MaxBTicks = 0;
  1824.           }
  1825.       }
  1826.     else
  1827.       {
  1828.         BTimeout.tv_sec = 0;
  1829.         BTimeout.tv_usec = ModemStatePolling * 1000;
  1830.         MaxBTicks = (BTimeout.tv_usec * CLOCKS_PER_SEC) / (1000 * 1000);
  1831.       }
  1832.     
  1833.     /* Logs sredird start */
  1834.     LogMsg(LOG_NOTICE,"SRedird started");
  1835.     
  1836.     /* Logs sredird log level */
  1837.     sprintf(LogStr,"Log level: %i",MaxLogLevel);
  1838.     LogMsg(LOG_INFO,LogStr);
  1839.  
  1840.     /* Logs the polling interval */
  1841.     sprintf(LogStr,"Polling interval (ms): %u",(unsigned int) (BTimeout.tv_usec / 1000));
  1842.     LogMsg(LOG_INFO,LogStr);
  1843.     
  1844.     /* Gets device and lock file names */
  1845.     DeviceName = argv[2];
  1846.     LockFileName = argv[3];
  1847.  
  1848.     /* Register exit and signal handler functions */
  1849.     atexit(ExitFunction);   
  1850.     signal(SIGHUP,SignalFunction);
  1851.     signal(SIGQUIT,SignalFunction);
  1852.     signal(SIGABRT,SignalFunction);
  1853.     signal(SIGPIPE,SignalFunction);
  1854.     signal(SIGTERM,SignalFunction);
  1855.     
  1856.     /* Register the function to be called on break condition */
  1857.     signal(SIGINT,BreakFunction);
  1858.  
  1859.       /* Try to lock the device */
  1860.       if (HDBLockFile(LockFileName,getpid()) != LockOk)
  1861.       {
  1862.           /* Lock failed */
  1863.           sprintf(LogStr,"Unable to lock %s. Exiting",LockFileName);
  1864.           LogMsg(LOG_NOTICE,LogStr);
  1865.           return(Error);
  1866.       }
  1867.       else
  1868.       {
  1869.           /* Lock succeeded */
  1870.           sprintf(LogStr,"Device %s locked",DeviceName);
  1871.           LogMsg(LOG_INFO,LogStr);
  1872.       }
  1873.  
  1874.       /* Open the device */
  1875.       if ((DeviceFd = open(DeviceName,O_RDWR | O_NOCTTY | O_NDELAY,0)) == OpenError)
  1876.       {
  1877.           /* Open failed */
  1878.           sprintf(LogStr,"Device in use.  Come back later.\r\n");
  1879.           write(STDOUT_FILENO,LogStr,strlen(LogStr));
  1880.           sprintf(LogStr,"Unable to open device %s. Exiting",DeviceName);
  1881.           LogMsg(LOG_ERR,LogStr);
  1882.           return(Error);
  1883.       }
  1884.       else
  1885.           DeviceOpened = True;
  1886.     
  1887.       /* Get the actual port settings */
  1888.       tcgetattr(DeviceFd,&InitialPortSettings);
  1889.       InitPortRetrieved = True;
  1890.       tcgetattr(DeviceFd,&PortSettings);
  1891.  
  1892.       /* Set the serial port to raw mode */
  1893.       cfmakeraw(&PortSettings);
  1894.  
  1895.       /* Enable HANGUP on close and disable modem control line handling */
  1896.       PortSettings.c_cflag = (PortSettings.c_cflag | HUPCL) | CLOCAL;
  1897.  
  1898.       /* Enable break handling */
  1899.       PortSettings.c_iflag = (PortSettings.c_iflag & ~IGNBRK) | BRKINT;
  1900.  
  1901.       /* Write the port settings to device */
  1902.       tcsetattr(DeviceFd,TCSANOW,&PortSettings);
  1903.  
  1904.       /* Reset the device fd to blocking mode */
  1905.       if (fcntl(DeviceFd,F_SETFL,fcntl(DeviceFd,F_GETFL) & ~(O_NDELAY)) == OpenError)
  1906.           LogMsg(LOG_ERR,"Unable to reset device to non blocking mode, ignoring");
  1907.  
  1908.       /* Initialize the input buffer */
  1909.       InitBuffer(&ToDevBuf);
  1910.       InitBuffer(&ToNetBuf);
  1911.  
  1912.       /* Setup sockets for low latency and automatic keepalive;
  1913.        * doesn't check if anything fails because failure doesn't prevent
  1914.        * correct functioning but only provides slightly worse behaviour 
  1915.        */
  1916.       SockParm = IPTOS_LOWDELAY;
  1917.       setsockopt(STDIN_FILENO,SOL_SOCKET,SO_KEEPALIVE,&SockParmEnable,sizeof(SockParmEnable));
  1918.       setsockopt(STDIN_FILENO,SOL_IP,IP_TOS,&SockParm,sizeof(SockParm));
  1919.       setsockopt(STDIN_FILENO,SOL_SOCKET,SO_OOBINLINE,&SockParmEnable,sizeof(SockParmEnable));
  1920.       setsockopt(STDOUT_FILENO,SOL_SOCKET,SO_KEEPALIVE,&SockParmEnable,sizeof(SockParmEnable));
  1921.       setsockopt(STDOUT_FILENO,SOL_IP,IP_TOS,&SockParm,sizeof(SockParm));
  1922.  
  1923.       /* Make reads/writes unblocking */
  1924.       ioctl(STDOUT_FILENO,FIONBIO,&SockParmEnable);
  1925.       ioctl(STDIN_FILENO,FIONBIO,&SockParmEnable);
  1926.       ioctl(DeviceFd,FIONBIO,&SockParmEnable);
  1927.  
  1928.  
  1929.     /* Send initial Telnet negotiations to the client */
  1930.     InitTelnetStateMachine();
  1931.     SendTelnetOption(&ToNetBuf,TNWILL,TN_TRANSMIT_BINARY);
  1932.     tnstate[TN_TRANSMIT_BINARY].sent_will = 1;
  1933.     SendTelnetOption(&ToNetBuf,TNDO,TN_TRANSMIT_BINARY);
  1934.     tnstate[TN_TRANSMIT_BINARY].sent_do = 1;
  1935.     SendTelnetOption(&ToNetBuf,TNWILL,TN_ECHO);
  1936.     tnstate[TN_ECHO].sent_will = 1;
  1937.     SendTelnetOption(&ToNetBuf,TNWILL,TN_SUPPRESS_GO_AHEAD);
  1938.     tnstate[TN_SUPPRESS_GO_AHEAD].sent_will = 1;
  1939.     SendTelnetOption(&ToNetBuf,TNDO,TN_SUPPRESS_GO_AHEAD);
  1940.     tnstate[TN_SUPPRESS_GO_AHEAD].sent_do = 1;
  1941.     SendTelnetOption(&ToNetBuf,TNDO,TNCOM_PORT_OPTION);
  1942.     tnstate[TNCOM_PORT_OPTION].sent_do = 1;
  1943.  
  1944.       /* Set up fd sets */
  1945.       /* Initially we have to read from all, but we only have data to send 
  1946.        * to the network */
  1947.       FD_ZERO(&InFdSet);
  1948.       FD_SET(STDIN_FILENO,&InFdSet);
  1949.       FD_SET(DeviceFd,&InFdSet);
  1950.       FD_ZERO(&OutFdSet);
  1951.       FD_SET(STDOUT_FILENO,&OutFdSet);
  1952.  
  1953.       /* Set up timeout for modem status polling */
  1954.       if (ETimeout != NULL)
  1955.           *ETimeout = BTimeout;
  1956.  
  1957.  
  1958.       /* Main loop with fd's control */
  1959.       while (True)
  1960.       {
  1961.           if (select(DeviceFd + 1,&InFdSet,&OutFdSet,NULL,ETimeout) > 0)
  1962.           {
  1963.               /* Handle buffers in the following order 
  1964.                *   Error
  1965.                *   Output
  1966.                *   Input
  1967.                * In other words, ensure we can write, make room, read more data
  1968.                */
  1969.  
  1970.               if (FD_ISSET(DeviceFd,&OutFdSet)) {
  1971.                   /* Write to serial port */
  1972.                   while ( !IsBufferEmpty(&ToDevBuf) ) {
  1973.                       int x;
  1974.                       C = GetFromBuffer(&ToDevBuf);
  1975.                       x = write(DeviceFd,&C,1);
  1976.                       if (x < 0 && errno == EWOULDBLOCK) {
  1977.                           PushToBuffer(&ToDevBuf,C);
  1978.                           break;
  1979.                       } else if (x < 1) {
  1980.                           LogMsg(LOG_NOTICE,"Error writing to device");
  1981.                           return(NoError);
  1982.                       }
  1983.                   }
  1984.               }
  1985.  
  1986.               if (FD_ISSET(STDOUT_FILENO,&OutFdSet)) {
  1987.                   /* Write to network */
  1988.                   while ( !IsBufferEmpty(&ToNetBuf) ) {
  1989.                       int x;
  1990.                       C = GetFromBuffer(&ToNetBuf);
  1991.                       x = write(STDOUT_FILENO,&C,1);
  1992.                       if (x < 0 && errno == EWOULDBLOCK) {
  1993.                           PushToBuffer(&ToNetBuf,C);
  1994.                           break;
  1995.                       } else if (x < 1) {
  1996.                           LogMsg(LOG_NOTICE,"Error writing to network");
  1997.                           return(NoError);
  1998.                       }
  1999.                   }
  2000.               }
  2001.  
  2002.               if (FD_ISSET(DeviceFd,&InFdSet)) {
  2003.                   /* Read from serial port */
  2004.                   while ( !IsBufferFull(&ToNetBuf) ) {
  2005.                       int x;
  2006.                       x = read(DeviceFd,&C,1);
  2007.                       if (x < 0 && errno == EWOULDBLOCK) {
  2008.                           break;
  2009.                       } else if (x < 1) {
  2010.                           LogMsg(LOG_NOTICE,"Error reading from device");
  2011.                           return(NoError);
  2012.                       } 
  2013.                       EscWriteChar(&ToNetBuf,C);
  2014.                   }
  2015.               }
  2016.  
  2017.               if (FD_ISSET(STDIN_FILENO,&InFdSet)) {
  2018.                   /* Read from network */
  2019.                   while ( !IsBufferFull(&ToDevBuf) ) {
  2020.                       int x;
  2021.                       x = read(STDIN_FILENO,&C,1);
  2022.                       if (x < 0 && errno == EWOULDBLOCK) {
  2023.                           break;
  2024.                       } else if (x < 1) {
  2025.                           LogMsg(LOG_NOTICE,"Error reading from network");
  2026.                           return(NoError);
  2027.                       } 
  2028.                       EscRedirectChar(&ToNetBuf,&ToDevBuf,DeviceFd,C);
  2029.                   }
  2030.               }
  2031.  
  2032.  
  2033.               /* Check if the buffer is not full and remote flow is off */
  2034.               if (RemoteFlowOff == True && IsBufferFull(&ToDevBuf) == False)
  2035.               {
  2036.                   /* Send a flow control resume command */
  2037.                   SendCPCFlowCommand(&ToNetBuf,TNASC_FLOWCONTROL_RESUME);
  2038.                   RemoteFlowOff = False;
  2039.               }
  2040.           }
  2041.  
  2042.           /* Check the port state and notify the client if it's changed */
  2043.           if (TCPCEnabled == True && InputFlow == True)
  2044.           {
  2045.               if ((GetModemState(DeviceFd,ModemState) & ModemStateMask &
  2046.                     ModemStateECMask) != (ModemState & ModemStateMask &
  2047.                                            ModemStateECMask))
  2048.               {
  2049.                   ModemState = GetModemState(DeviceFd,ModemState);
  2050.                   SendCPCByteCommand(&ToNetBuf,TNASC_NOTIFY_MODEMSTATE,
  2051.                                       (ModemState & ModemStateMask));
  2052.                   sprintf(LogStr,"Sent modem state: %u",
  2053.                            (unsigned int) (ModemState & ModemStateMask));
  2054.                   LogMsg(LOG_DEBUG,LogStr);
  2055.               }
  2056. #ifdef COMMENT 
  2057.               /* GetLineState() not yet implemented */
  2058.               if ((GetLineState(DeviceFd,LineState) & LineStateMask &
  2059.                     LineStateECMask) != (LineState & LineStateMask &
  2060.                                            LineStateECMask))
  2061.               {
  2062.                   LineState = GetLineState(DeviceFd,LineState);
  2063.                   SendCPCByteCommand(&ToNetBuf,TNASC_NOTIFY_LINESTATE,
  2064.                                       (LineState & LineStateMask));
  2065.                   sprintf(LogStr,"Sent line state: %u",
  2066.                            (unsigned int) (LineState & LineStateMask));
  2067.                   LogMsg(LOG_DEBUG,LogStr);
  2068.               }
  2069. #endif /* COMMENT */
  2070.           }
  2071.   
  2072.           /* Resets the fd sets */
  2073.           FD_ZERO(&InFdSet);        
  2074.           /* Check if the buffer is not full */
  2075.           if (IsBufferFull(&ToDevBuf) == False) {
  2076.               FD_SET(STDIN_FILENO,&InFdSet);
  2077.           } else if (RemoteFlowOff == False)
  2078.           {
  2079.               /* Send a flow control suspend command */
  2080.               SendCPCFlowCommand(&ToNetBuf,TNASC_FLOWCONTROL_SUSPEND);
  2081.               RemoteFlowOff = True;
  2082.           }
  2083.  
  2084.           /* If input flow has been disabled from the remote client
  2085.           don't read from the device */
  2086.           if (!IsBufferFull(&ToNetBuf) && InputFlow == True)
  2087.               FD_SET(DeviceFd,&InFdSet);
  2088.  
  2089.           FD_ZERO(&OutFdSet);
  2090.           /* Check if there are characters available to write */
  2091.           if (!IsBufferEmpty(&ToDevBuf))
  2092.               FD_SET(DeviceFd,&OutFdSet);
  2093.           if (!IsBufferEmpty(&ToNetBuf))
  2094.               FD_SET(STDOUT_FILENO,&OutFdSet);
  2095.  
  2096.           /* Set up timeout for modem status polling */
  2097.           if (ETimeout != NULL)
  2098.               *ETimeout = BTimeout;
  2099.       }   
  2100. }
  2101.