home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / sredird / old / sredird.c < prev   
C/C++ Source or Header  |  2003-07-08  |  67KB  |  2,190 lines

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