DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/serialport/nullmodem.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 
00022 #if C_MODEM
00023 
00024 #include "control.h"
00025 #include "serialport.h"
00026 #include "nullmodem.h"
00027 
00028 CNullModem::CNullModem(Bitu id, CommandLine* cmd):CSerial (id, cmd) {
00029         Bitu temptcpport=23;
00030         memset(&telClient, 0, sizeof(telClient));
00031         InstallationSuccessful = false;
00032         serversocket = 0;
00033         clientsocket = 0;
00034         serverport = 0;
00035         clientport = 0;
00036 
00037         rx_retry = 0;
00038         rx_retry_max = 20;
00039         rx_state=N_RX_DISC;
00040 
00041         tx_gather = 12;
00042         
00043         dtrrespect=false;
00044         tx_block=false;
00045         receiveblock=false;
00046         transparent=false;
00047     nonlocal=false;
00048         telnet=false;
00049         
00050         Bitu bool_temp=0;
00051 
00052         // usedtr: The nullmodem will
00053         // 1) when it is client connect to the server not immediately but
00054         //    as soon as a modem-aware application is started (DTR is switched on).
00055         // 2) only receive data when DTR is on.
00056         if (getBituSubstring("usedtr:", &bool_temp, cmd)) {
00057                 if (bool_temp==1) {
00058                         dtrrespect=true;
00059                         transparent=true;
00060                         DTR_delta=false; // connect immediately when DTR is already 1
00061                 }
00062         }
00063         // transparent: don't add additional handshake control.
00064         if (getBituSubstring("transparent:", &bool_temp, cmd)) {
00065                 if (bool_temp==1) transparent=true;
00066                 else transparent=false;
00067         }
00068     // nonlocal: enable connections not originating from localhost.
00069     //           otherwise, connections not coming from localhost are rejected for security reasons.
00070     if (getBituSubstring("nonlocal:", &bool_temp, cmd)) {
00071         if (bool_temp==1) {
00072             nonlocal=true;
00073         }
00074         }
00075         // telnet: interpret telnet commands.
00076         if (getBituSubstring("telnet:", &bool_temp, cmd)) {
00077                 if (bool_temp==1) {
00078                         transparent=true;
00079                         telnet=true;
00080                 }
00081         }
00082         // rxdelay: How many milliseconds to wait before causing an
00083         // overflow when the application is unresponsive.
00084         if (getBituSubstring("rxdelay:", &rx_retry_max, cmd)) {
00085                 if (!(rx_retry_max<=10000)) {
00086                         rx_retry_max=50;
00087                 }
00088         }
00089         // txdelay: How many milliseconds to wait before sending data.
00090         // This reduces network overhead quite a lot.
00091         if (getBituSubstring("txdelay:", &tx_gather, cmd)) {
00092                 if (!(tx_gather<=500)) {
00093                         tx_gather=12;
00094                 }
00095         }
00096         // port is for both server and client
00097         if (getBituSubstring("port:", &temptcpport, cmd)) {
00098                 if (!(temptcpport>0&&temptcpport<65536)) {
00099                         temptcpport=23;
00100                 }
00101         }
00102         // socket inheritance (client-alike)
00103         if (getBituSubstring("inhsocket:", &bool_temp, cmd)) {
00104 #ifdef NATIVESOCKETS
00105                 if (Netwrapper_GetCapabilities()&NETWRAPPER_TCP_NATIVESOCKET) {
00106                         if (bool_temp==1) {
00107                                 int sock;
00108                                 if (control->cmdline->FindInt("-socket",sock,true)) {
00109                                         dtrrespect=false;
00110                                         transparent=true;
00111                                         LOG_MSG("Inheritance socket handle: %d",sock);
00112                                         if (!ClientConnect(new TCPClientSocket(sock)))
00113                                                 return;
00114                                 } else {
00115                                         LOG_MSG("Serial%d: -socket parameter missing.",(int)COMNUMBER);
00116                                         return;
00117                                 }
00118                         }
00119                 } else {
00120                         LOG_MSG("Serial%d: socket inheritance not supported on this platform.",(int)COMNUMBER);
00121                         return;
00122                 }
00123 #else
00124                 LOG_MSG("Serial%d: socket inheritance not available.",(int)COMNUMBER);
00125 #endif
00126         } else {
00127                 // normal server/client
00128                 std::string tmpstring;
00129                 if (cmd->FindStringBegin("server:",tmpstring,false)) {
00130                         // we are a client
00131                         const char* hostnamechar=tmpstring.c_str();
00132                         size_t hostlen=strlen(hostnamechar)+1;
00133                         if (hostlen>sizeof(hostnamebuffer)) {
00134                                 hostlen=sizeof(hostnamebuffer);
00135                                 hostnamebuffer[sizeof(hostnamebuffer)-1]=0;
00136                         }
00137                         memcpy(hostnamebuffer,hostnamechar,hostlen);
00138                         clientport=(Bit16u)temptcpport;
00139                         if (dtrrespect) {
00140                                 // we connect as soon as DTR is switched on
00141                                 setEvent(SERIAL_NULLMODEM_DTR_EVENT, 50);
00142                                 LOG_MSG("Serial%d: Waiting for DTR...",(int)COMNUMBER);
00143                         } else if (!ClientConnect(
00144                                 new TCPClientSocket((char*)hostnamebuffer,(Bit16u)clientport)))
00145                                 return;
00146                 } else {
00147                         // we are a server
00148                         serverport = (Bit16u)temptcpport;
00149                         if (!ServerListen()) return;
00150                 }
00151         }
00152         CSerial::Init_Registers();
00153         InstallationSuccessful = true;
00154 
00155         setCTS(dtrrespect||transparent);
00156         setDSR(dtrrespect||transparent);
00157         setRI(false);
00158         setCD(clientsocket != 0); // CD on if connection established
00159 }
00160 
00161 CNullModem::~CNullModem() {
00162         if (serversocket) delete serversocket;
00163         if (clientsocket) delete clientsocket;
00164         // remove events
00165         for(Bit16u i = SERIAL_BASE_EVENT_COUNT+1;
00166                         i <= SERIAL_NULLMODEM_EVENT_COUNT; i++) {
00167                 removeEvent(i);
00168         }
00169 }
00170 
00171 void CNullModem::WriteChar(Bit8u data) {
00172         if (clientsocket)clientsocket->SendByteBuffered(data);
00173         if (!tx_block) {
00174                 //LOG_MSG("setevreduct");
00175                 setEvent(SERIAL_TX_REDUCTION, (float)tx_gather);
00176                 tx_block=true;
00177         }
00178 }
00179 
00180 Bits CNullModem::readChar() {
00181         Bits rxchar = clientsocket->GetcharNonBlock();
00182         if (telnet && rxchar>=0) return TelnetEmulation((Bit8u)rxchar);
00183         else if (rxchar==0xff && !transparent) {// escape char
00184                 // get the next char
00185                 Bits rxchar = clientsocket->GetcharNonBlock();
00186                 if (rxchar==0xff) return rxchar; // 0xff 0xff -> 0xff was meant
00187                 rxchar&0x1? setCTS(true) : setCTS(false);
00188                 rxchar&0x2? setDSR(true) : setDSR(false);
00189                 if (rxchar&0x4) receiveByteEx(0x0,0x10);
00190                 return -1;      // no "payload" received
00191         } else return rxchar;
00192 }
00193 
00194 bool CNullModem::ClientConnect(TCPClientSocket* newsocket) {
00195         Bit8u peernamebuf[16];
00196         clientsocket = newsocket;
00197  
00198         if (!clientsocket->isopen) {
00199                 LOG_MSG("Serial%d: Connection failed.",(int)COMNUMBER);
00200                 delete clientsocket;
00201                 clientsocket=0;
00202                 setCD(false);
00203                 return false;
00204         }
00205         clientsocket->SetSendBufferSize(256);
00206         clientsocket->GetRemoteAddressString(peernamebuf);
00207         // transmit the line status
00208         if (!transparent) setRTSDTR(getRTS(), getDTR());
00209         rx_state=N_RX_IDLE;
00210         LOG_MSG("Serial%d: Connected to %s",(int)COMNUMBER,peernamebuf);
00211         setEvent(SERIAL_POLLING_EVENT, 1);
00212         setCD(true);
00213         return true;
00214 }
00215 
00216 bool CNullModem::ServerListen() {
00217         // Start the server listen port.
00218         serversocket = new TCPServerSocket(serverport);
00219         if (!serversocket->isopen) return false;
00220         LOG_MSG("Serial%d: Nullmodem server waiting for connection on port %d...",
00221                 (int)COMNUMBER,serverport);
00222         setEvent(SERIAL_SERVER_POLLING_EVENT, 50);
00223         setCD(false);
00224         return true;
00225 }
00226 
00227 bool CNullModem::ServerConnect() {
00228         // check if a connection is available.
00229         clientsocket=serversocket->Accept();
00230         if (!clientsocket) return false;
00231         
00232         Bit8u peeripbuf[16];
00233         clientsocket->GetRemoteAddressString(peeripbuf);
00234         LOG_MSG("Serial%d: A client (%s) has connected.",(int)COMNUMBER,peeripbuf);
00235 #if SERIAL_DEBUG
00236         log_ser(dbg_aux,"Nullmodem: A client (%s) has connected.", peeripbuf);
00237 #endif
00238 
00239     /* FIXME: It would be nice if the SDL net library had a bind() call to bind only to a specific interface.
00240      *        Or maybe it does... what am I missing? */
00241     if (!nonlocal && strcmp((char*)peeripbuf,"127.0.0.1") != 0) {
00242         LOG_MSG("Serial%d: Non-localhost client (%s) dropped by nonlocal:0 policy. To accept connections from network, set nonlocal:1",(int)COMNUMBER,peeripbuf);
00243         delete clientsocket;
00244         clientsocket = NULL;
00245         return false;
00246     }
00247 
00248         clientsocket->SetSendBufferSize(256);
00249         rx_state=N_RX_IDLE;
00250         setEvent(SERIAL_POLLING_EVENT, 1);
00251         
00252         // we don't accept further connections
00253         delete serversocket;
00254         serversocket=0;
00255 
00256         // transmit the line status
00257         setRTSDTR(getRTS(), getDTR());
00258         if (transparent) setCD(true);
00259         return true;
00260 }
00261 
00262 void CNullModem::Disconnect() {
00263         removeEvent(SERIAL_POLLING_EVENT);
00264         removeEvent(SERIAL_RX_EVENT);
00265         // it was disconnected; free the socket and restart the server socket
00266         LOG_MSG("Serial%d: Disconnected.",(int)COMNUMBER);
00267         delete clientsocket;
00268         clientsocket=0;
00269         setDSR(false);
00270         setCTS(false);
00271         setCD(false);
00272         
00273         if (serverport) {
00274                 serversocket = new TCPServerSocket(serverport);
00275                 if (serversocket->isopen) 
00276                         setEvent(SERIAL_SERVER_POLLING_EVENT, 50);
00277                 else delete serversocket;
00278         } else if (dtrrespect) {
00279                 setEvent(SERIAL_NULLMODEM_DTR_EVENT,50);
00280                 DTR_delta = getDTR(); // try to reconnect the next time DTR is set
00281         }
00282 }
00283 
00284 void CNullModem::handleUpperEvent(Bit16u type) {
00285         
00286         switch(type) {
00287                 case SERIAL_POLLING_EVENT: {
00288                         // periodically check if new data arrived, disconnect
00289                         // if required. Add it back.
00290                         setEvent(SERIAL_POLLING_EVENT, 1.0f);
00291                         // update Modem input line states
00292                         updateMSR();
00293                         switch(rx_state) {
00294                                 case N_RX_IDLE:
00295                                         if (CanReceiveByte()) {
00296                                                 if (doReceive()) {
00297                                                         // a byte was received
00298                                                         rx_state=N_RX_WAIT;
00299                                                         setEvent(SERIAL_RX_EVENT, bytetime*0.9f);
00300                                                 } // else still idle
00301                                         } else {
00302 #if SERIAL_DEBUG
00303                                                 log_ser(dbg_aux,"Nullmodem: block on polling.");
00304 #endif
00305                                                 rx_state=N_RX_BLOCKED;
00306                                                 // have both delays (1ms + bytetime)
00307                                                 setEvent(SERIAL_RX_EVENT, bytetime*0.9f);
00308                                         }
00309                                         break;
00310                                 case N_RX_BLOCKED:
00311                     // one timeout tick
00312                                         if (!CanReceiveByte()) {
00313                                                 rx_retry++;
00314                                                 if (rx_retry>=rx_retry_max) {
00315                                                         // it has timed out:
00316                                                         rx_retry=0;
00317                                                         removeEvent(SERIAL_RX_EVENT);
00318                                                         if (doReceive()) {
00319                                                                 // read away everything
00320                                                                 while(doReceive());
00321                                                                 rx_state=N_RX_WAIT;
00322                                                                 setEvent(SERIAL_RX_EVENT, bytetime*0.9f);
00323                                                         } else {
00324                                                                 // much trouble about nothing
00325                                 rx_state=N_RX_IDLE;
00326 #if SERIAL_DEBUG
00327                                                                 log_ser(dbg_aux,"Nullmodem: unblock due to no more data",rx_retry);
00328 #endif
00329                                                         }
00330                                                 } // else wait further
00331                                         } else {
00332                                                 // good: we can receive again
00333                                                 removeEvent(SERIAL_RX_EVENT);
00334                                                 rx_retry=0;
00335                                                 if (doReceive()) {
00336                                                         rx_state=N_RX_FASTWAIT;
00337                                                         setEvent(SERIAL_RX_EVENT, bytetime*0.65f);
00338                                                 } else {
00339                                                         // much trouble about nothing
00340                                                         rx_state=N_RX_IDLE;
00341                                                 }
00342                                         }
00343                                         break;
00344 
00345                                 case N_RX_WAIT:
00346                                 case N_RX_FASTWAIT:
00347                                         break;
00348                         }
00349                         break;
00350                 }
00351                 case SERIAL_RX_EVENT: {
00352                         switch(rx_state) {
00353                                 case N_RX_IDLE:
00354                                         LOG_MSG("internal error in nullmodem");
00355                                         break;
00356 
00357                                 case N_RX_BLOCKED: // try to receive
00358                                 case N_RX_WAIT:
00359                                 case N_RX_FASTWAIT:
00360                                         if (CanReceiveByte()) {
00361                                                 // just works or unblocked
00362                                                 if (doReceive()) {
00363                                                         rx_retry=0; // not waiting anymore
00364                                                         if (rx_state==N_RX_WAIT) setEvent(SERIAL_RX_EVENT, bytetime*0.9f);
00365                                                         else {
00366                                                                 // maybe unblocked
00367                                                                 rx_state=N_RX_FASTWAIT;
00368                                                                 setEvent(SERIAL_RX_EVENT, bytetime*0.65f);
00369                                                         }
00370                                                 } else {
00371                                                         // didn't receive anything
00372                                                         rx_retry=0;
00373                                                         rx_state=N_RX_IDLE;
00374                                                 }
00375                                         } else {
00376                                                 // blocking now or still blocked
00377 #if SERIAL_DEBUG
00378                                                 if (rx_state==N_RX_BLOCKED)
00379                                                         log_ser(dbg_aux,"Nullmodem: rx still blocked (retry=%d)",rx_retry);
00380                                                 else log_ser(dbg_aux,"Nullmodem: block on continued rx (retry=%d).",rx_retry);
00381 #endif
00382                                                 setEvent(SERIAL_RX_EVENT, bytetime*0.65f);
00383                                                 rx_state=N_RX_BLOCKED;
00384                                         }
00385 
00386                                         break;
00387                         }
00388                         break;
00389                 }
00390                 case SERIAL_TX_EVENT: {
00391                         // Maybe echo cirquit works a bit better this way
00392                         if (rx_state==N_RX_IDLE && CanReceiveByte() && clientsocket) {
00393                                 if (doReceive()) {
00394                                         // a byte was received
00395                                         rx_state=N_RX_WAIT;
00396                                         setEvent(SERIAL_RX_EVENT, bytetime*0.9f);
00397                                 }
00398                         }
00399                         ByteTransmitted();
00400                         break;
00401                 }
00402                 case SERIAL_THR_EVENT: {
00403                         ByteTransmitting();
00404                         // actually send it
00405                         setEvent(SERIAL_TX_EVENT,bytetime+0.01f);
00406                         break;                             
00407                 }
00408                 case SERIAL_SERVER_POLLING_EVENT: {
00409                         // As long as nothing is connected to our server poll the
00410                         // connection.
00411                         if (!ServerConnect()) {
00412                                 // continue looking
00413                                 setEvent(SERIAL_SERVER_POLLING_EVENT, 50);
00414                         }
00415                         break;
00416                 }
00417                 case SERIAL_TX_REDUCTION: {
00418                         // Flush the data in the transmitting buffer.
00419                         if (clientsocket) clientsocket->FlushBuffer();
00420                         tx_block=false;
00421                         break;                                            
00422                 }
00423                 case SERIAL_NULLMODEM_DTR_EVENT: {
00424                         if ((!DTR_delta) && getDTR()) {
00425                                 // DTR went positive. Try to connect.
00426                                 if (ClientConnect(new TCPClientSocket((char*)hostnamebuffer,
00427                                                                 (Bit16u)clientport)))
00428                                         break; // no more DTR wait event when connected
00429                         }
00430                         DTR_delta = getDTR();
00431                         setEvent(SERIAL_NULLMODEM_DTR_EVENT,50);
00432                         break;
00433                 }
00434         }
00435 }
00436 
00437 /*****************************************************************************/
00438 /* updatePortConfig is called when emulated app changes the serial port     **/
00439 /* parameters baudrate, stopbits, number of databits, parity.               **/
00440 /*****************************************************************************/
00441 void CNullModem::updatePortConfig (Bit16u /*divider*/, Bit8u /*lcr*/) {
00442         
00443 }
00444 
00445 void CNullModem::updateMSR () {
00446         
00447 }
00448 
00449 bool CNullModem::doReceive () {
00450                 Bits rxchar = readChar();
00451                 if (rxchar>=0) {
00452                         receiveByteEx((Bit8u)rxchar,0);
00453                         return true;
00454                 }
00455                 else if (rxchar==-2) {
00456                         Disconnect();
00457                 }
00458                 return false;
00459 }
00460  
00461 void CNullModem::transmitByte (Bit8u val, bool first) {
00462         // transmit it later in THR_Event
00463         if (first) setEvent(SERIAL_THR_EVENT, bytetime/8);
00464         else setEvent(SERIAL_TX_EVENT, bytetime);
00465 
00466         // disable 0xff escaping when transparent mode is enabled
00467         if (!transparent && (val==0xff)) WriteChar(0xff);
00468         
00469         WriteChar(val);
00470 }
00471 
00472 Bits CNullModem::TelnetEmulation(Bit8u data) {
00473         Bit8u response[3];
00474         if (telClient.inIAC) {
00475                 if (telClient.recCommand) {
00476                         if ((data != 0) && (data != 1) && (data != 3)) {
00477                                 LOG_MSG("Serial%d: Unrecognized telnet option %d",(int)COMNUMBER, data);
00478                                 if (telClient.command>250) {
00479                                         /* Reject anything we don't recognize */
00480                                         response[0]=0xff;
00481                                         response[1]=252;
00482                                         response[2]=data; /* We won't do crap! */
00483                                         if (clientsocket) clientsocket->SendArray(response, 3);
00484                                 }
00485                         }
00486                         switch(telClient.command) {
00487                                 case 251: /* Will */
00488                                         if (data == 0) telClient.binary[TEL_SERVER] = true;
00489                                         if (data == 1) telClient.echo[TEL_SERVER] = true;
00490                                         if (data == 3) telClient.supressGA[TEL_SERVER] = true;
00491                                         break;
00492                                 case 252: /* Won't */
00493                                         if (data == 0) telClient.binary[TEL_SERVER] = false;
00494                                         if (data == 1) telClient.echo[TEL_SERVER] = false;
00495                                         if (data == 3) telClient.supressGA[TEL_SERVER] = false;
00496                                         break;
00497                                 case 253: /* Do */
00498                                         if (data == 0) {
00499                                                 telClient.binary[TEL_CLIENT] = true;
00500                                                         response[0]=0xff;
00501                                                         response[1]=251;
00502                                                         response[2]=0; /* Will do binary transfer */
00503                                                         if (clientsocket) clientsocket->SendArray(response, 3);
00504                                         }
00505                                         if (data == 1) {
00506                                                 telClient.echo[TEL_CLIENT] = false;
00507                                                         response[0]=0xff;
00508                                                         response[1]=252;
00509                                                         response[2]=1; /* Won't echo (too lazy) */
00510                                                         if (clientsocket) clientsocket->SendArray(response, 3);
00511                                         }
00512                                         if (data == 3) {
00513                                                 telClient.supressGA[TEL_CLIENT] = true;
00514                                                         response[0]=0xff;
00515                                                         response[1]=251;
00516                                                         response[2]=3; /* Will Suppress GA */
00517                                                         if (clientsocket) clientsocket->SendArray(response, 3);
00518                                         }
00519                                         break;
00520                                 case 254: /* Don't */
00521                                         if (data == 0) {
00522                                                 telClient.binary[TEL_CLIENT] = false;
00523                                                 response[0]=0xff;
00524                                                 response[1]=252;
00525                                                 response[2]=0; /* Won't do binary transfer */
00526                                                 if (clientsocket) clientsocket->SendArray(response, 3);
00527                                         }
00528                                         if (data == 1) {
00529                                                 telClient.echo[TEL_CLIENT] = false;
00530                                                 response[0]=0xff;
00531                                                 response[1]=252;
00532                                                 response[2]=1; /* Won't echo (fine by me) */
00533                                                 if (clientsocket) clientsocket->SendArray(response, 3);
00534                                         }
00535                                         if (data == 3) {
00536                                                 telClient.supressGA[TEL_CLIENT] = true;
00537                                                 response[0]=0xff;
00538                                                 response[1]=251;
00539                                                 response[2]=3; /* Will Suppress GA (too lazy) */
00540                                                 if (clientsocket) clientsocket->SendArray(response, 3);
00541                                         }
00542                                         break;
00543                                 default:
00544                                         LOG_MSG("MODEM: Telnet client sent IAC %d", telClient.command);
00545                                         break;
00546                         }
00547                         telClient.inIAC = false;
00548                         telClient.recCommand = false;
00549                         return -1; //continue;
00550                 } else {
00551                         if (data==249) {
00552                                 /* Go Ahead received */
00553                                 telClient.inIAC = false;
00554                                 return -1; //continue;
00555                         }
00556                         telClient.command = data;
00557                         telClient.recCommand = true;
00558                         
00559                         if ((telClient.binary[TEL_SERVER]) && (data == 0xff)) {
00560                                 /* Binary data with value of 255 */
00561                                 telClient.inIAC = false;
00562                                 telClient.recCommand = false;
00563                                         return 0xff;
00564                         }
00565                 }
00566         } else {
00567                 if (data == 0xff) {
00568                         telClient.inIAC = true;
00569                         return -1;
00570                 }
00571                 return data;
00572         }
00573         return -1; // ???
00574 }
00575         
00576 
00577 /*****************************************************************************/
00578 /* setBreak(val) switches break on or off                                   **/
00579 /*****************************************************************************/
00580 
00581 void CNullModem::setBreak (bool /*value*/) {
00582         CNullModem::setRTSDTR(getRTS(), getDTR());
00583 }
00584 
00585 /*****************************************************************************/
00586 /* updateModemControlLines(mcr) sets DTR and RTS.                           **/
00587 /*****************************************************************************/
00588 void CNullModem::setRTSDTR(bool xrts, bool xdtr) {
00589         if (!transparent) {
00590                 Bit8u control[2];
00591                 control[0]=0xff;
00592                 control[1]=0x0;
00593                 if (xrts) control[1]|=1;
00594                 if (xdtr) control[1]|=2;
00595                 if (LCR&LCR_BREAK_MASK) control[1]|=4;
00596                 if (clientsocket) clientsocket->SendArray(control, 2);
00597         }
00598 }
00599 void CNullModem::setRTS(bool val) {
00600         setRTSDTR(val, getDTR());
00601 }
00602 void CNullModem::setDTR(bool val) {
00603         setRTSDTR(getRTS(), val);
00604 }
00605 #endif