OpenCores
URL https://opencores.org/ocsvn/w11/w11/trunk

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.6/] [tools/] [src/] [librw11/] [Rw11VirtTermTcp.cpp] - Diff between revs 22 and 24

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 22 Rev 24
// $Id: Rw11VirtTermTcp.cpp 521 2013-05-20 22:16:45Z mueller $
// $Id: Rw11VirtTermTcp.cpp 521 2013-05-20 22:16:45Z mueller $
//
//
// Copyright 2013- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
// Copyright 2013- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
//
//
// This program is free software; you may redistribute and/or modify it under
// This program is free software; you may redistribute and/or modify it under
// the terms of the GNU General Public License as published by the Free
// the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 2, or at your option any later version.
// Software Foundation, either version 2, or at your option any later version.
//
//
// This program is distributed in the hope that it will be useful, but
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for complete details.
// for complete details.
// 
// 
// Revision History: 
// Revision History: 
// Date         Rev Version  Comment
// Date         Rev Version  Comment
// 2013-05-17   512   1.0.3  use Rtools::String2Long
// 2013-05-17   512   1.0.3  use Rtools::String2Long
// 2013-05-05   516   1.0.2  fix mistakes in emsg generation with errno
// 2013-05-05   516   1.0.2  fix mistakes in emsg generation with errno
// 2013-04-20   508   1.0.1  add fSndPreConQue handling
// 2013-04-20   508   1.0.1  add fSndPreConQue handling
// 2013-03-06   495   1.0    Initial version
// 2013-03-06   495   1.0    Initial version
// 2013-02-13   488   0.1    First draft
// 2013-02-13   488   0.1    First draft
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
 
 
/*!
/*!
  \file
  \file
  \version $Id: Rw11VirtTermTcp.cpp 521 2013-05-20 22:16:45Z mueller $
  \version $Id: Rw11VirtTermTcp.cpp 521 2013-05-20 22:16:45Z mueller $
  \brief   Implemenation of Rw11VirtTermTcp.
  \brief   Implemenation of Rw11VirtTermTcp.
*/
*/
 
 
#include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netdb.h>
#include <string.h>
#include <string.h>
 
 
#include <sstream>
#include <sstream>
 
 
#include "librtools/RosFill.hpp"
#include "librtools/RosFill.hpp"
#include "librtools/RlogMsg.hpp"
#include "librtools/RlogMsg.hpp"
 
 
#include "Rw11VirtTermTcp.hpp"
#include "Rw11VirtTermTcp.hpp"
 
 
using namespace std;
using namespace std;
 
 
/*!
/*!
  \class Retro::Rw11VirtTermTcp
  \class Retro::Rw11VirtTermTcp
  \brief FIXME_docs
  \brief FIXME_docs
*/
*/
 
 
// all method definitions in namespace Retro
// all method definitions in namespace Retro
namespace Retro {
namespace Retro {
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
// constants definitions
// constants definitions
 
 
const uint8_t  Rw11VirtTermTcp::kCode_NULL;
const uint8_t  Rw11VirtTermTcp::kCode_NULL;
const uint8_t  Rw11VirtTermTcp::kCode_LF;
const uint8_t  Rw11VirtTermTcp::kCode_LF;
const uint8_t  Rw11VirtTermTcp::kCode_CR;
const uint8_t  Rw11VirtTermTcp::kCode_CR;
const uint8_t  Rw11VirtTermTcp::kCode_ESC;
const uint8_t  Rw11VirtTermTcp::kCode_ESC;
const uint8_t  Rw11VirtTermTcp::kCode_SE;
const uint8_t  Rw11VirtTermTcp::kCode_SE;
const uint8_t  Rw11VirtTermTcp::kCode_NOP;
const uint8_t  Rw11VirtTermTcp::kCode_NOP;
const uint8_t  Rw11VirtTermTcp::kCode_IP;
const uint8_t  Rw11VirtTermTcp::kCode_IP;
const uint8_t  Rw11VirtTermTcp::kCode_GA;
const uint8_t  Rw11VirtTermTcp::kCode_GA;
const uint8_t  Rw11VirtTermTcp::kCode_SB;
const uint8_t  Rw11VirtTermTcp::kCode_SB;
const uint8_t  Rw11VirtTermTcp::kCode_WILL;
const uint8_t  Rw11VirtTermTcp::kCode_WILL;
const uint8_t  Rw11VirtTermTcp::kCode_WONT;
const uint8_t  Rw11VirtTermTcp::kCode_WONT;
const uint8_t  Rw11VirtTermTcp::kCode_DO;
const uint8_t  Rw11VirtTermTcp::kCode_DO;
const uint8_t  Rw11VirtTermTcp::kCode_DONT;
const uint8_t  Rw11VirtTermTcp::kCode_DONT;
const uint8_t  Rw11VirtTermTcp::kCode_IAC;
const uint8_t  Rw11VirtTermTcp::kCode_IAC;
 
 
const uint8_t  Rw11VirtTermTcp::kOpt_BIN;
const uint8_t  Rw11VirtTermTcp::kOpt_BIN;
const uint8_t  Rw11VirtTermTcp::kOpt_ECHO;
const uint8_t  Rw11VirtTermTcp::kOpt_ECHO;
const uint8_t  Rw11VirtTermTcp::kOpt_SGA;
const uint8_t  Rw11VirtTermTcp::kOpt_SGA;
const uint8_t  Rw11VirtTermTcp::kOpt_TTYP;
const uint8_t  Rw11VirtTermTcp::kOpt_TTYP;
const uint8_t  Rw11VirtTermTcp::kOpt_LINE;
const uint8_t  Rw11VirtTermTcp::kOpt_LINE;
 
 
const size_t   Rw11VirtTermTcp::kPreConQue_limit;
const size_t   Rw11VirtTermTcp::kPreConQue_limit;
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! Default constructor
//! Default constructor
 
 
Rw11VirtTermTcp::Rw11VirtTermTcp(Rw11Unit* punit)
Rw11VirtTermTcp::Rw11VirtTermTcp(Rw11Unit* punit)
  : Rw11VirtTerm(punit),
  : Rw11VirtTerm(punit),
    fFdListen(-1),
    fFdListen(-1),
    fFd(-1),
    fFd(-1),
    fState(ts_Closed),
    fState(ts_Closed),
    fTcpTrace(false),
    fTcpTrace(false),
    fSndPreConQue()
    fSndPreConQue()
{
{
  fStats.Define(kStatNVTPreConSave , "NVTPreConSave" ,
  fStats.Define(kStatNVTPreConSave , "NVTPreConSave" ,
                "VT snd bytes saved prior connect");
                "VT snd bytes saved prior connect");
  fStats.Define(kStatNVTPreConDrop , "NVTPreConDrop" ,
  fStats.Define(kStatNVTPreConDrop , "NVTPreConDrop" ,
                "VT snd bytes dropped prior connect");
                "VT snd bytes dropped prior connect");
  fStats.Define(kStatNVTListenPoll , "NVTListenPoll" ,
  fStats.Define(kStatNVTListenPoll , "NVTListenPoll" ,
                "VT ListenPollHandler() calls");
                "VT ListenPollHandler() calls");
  fStats.Define(kStatNVTAccept,      "NVTAccept",     "VT socket accepts");
  fStats.Define(kStatNVTAccept,      "NVTAccept",     "VT socket accepts");
  fStats.Define(kStatNVTRcvRaw,      "NVTRcvRaw",     "VT raw bytes received");
  fStats.Define(kStatNVTRcvRaw,      "NVTRcvRaw",     "VT raw bytes received");
  fStats.Define(kStatNVTSndRaw,      "NVTSndRaw",     "VT raw bytes send");
  fStats.Define(kStatNVTSndRaw,      "NVTSndRaw",     "VT raw bytes send");
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! Destructor
//! Destructor
 
 
Rw11VirtTermTcp::~Rw11VirtTermTcp()
Rw11VirtTermTcp::~Rw11VirtTermTcp()
{
{
  if (fFdListen > 2) {
  if (fFdListen > 2) {
    Server().RemovePollHandler(fFdListen);
    Server().RemovePollHandler(fFdListen);
    close(fFdListen);
    close(fFdListen);
  }
  }
  if (Connected()) {
  if (Connected()) {
    Server().RemovePollHandler(fFd);
    Server().RemovePollHandler(fFd);
    close(fFd);
    close(fFd);
  }
  }
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! FIXME_docs
 
 
bool Rw11VirtTermTcp::Open(const std::string& url, RerrMsg& emsg)
bool Rw11VirtTermTcp::Open(const std::string& url, RerrMsg& emsg)
{
{
  if (!fUrl.Set(url, "|port=|trace|", emsg)) return false;
  if (!fUrl.Set(url, "|port=|trace|", emsg)) return false;
  if (!(fUrl.FindOpt("port"))) {
  if (!(fUrl.FindOpt("port"))) {
    emsg.Init("Rw11VirtTermTcp::Open", "port= option not specified");
    emsg.Init("Rw11VirtTermTcp::Open", "port= option not specified");
    return false;
    return false;
  }
  }
 
 
  fTcpTrace = fUrl.FindOpt("trace");
  fTcpTrace = fUrl.FindOpt("trace");
 
 
  string port;
  string port;
  fUrl.FindOpt("port",port);
  fUrl.FindOpt("port",port);
  unsigned long portno;
  unsigned long portno;
  if (!Rtools::String2Long(port, portno, emsg)) return false;
  if (!Rtools::String2Long(port, portno, emsg)) return false;
 
 
  protoent* pe = getprotobyname("tcp");
  protoent* pe = getprotobyname("tcp");
  if (pe == 0) {
  if (pe == 0) {
    emsg.Init("Rw11VirtTermTcp::Open","getprotobyname(\"tcp\") failed");
    emsg.Init("Rw11VirtTermTcp::Open","getprotobyname(\"tcp\") failed");
    return false;
    return false;
  }
  }
 
 
  int fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, pe->p_proto);
  int fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, pe->p_proto);
  if (fd < 0) {
  if (fd < 0) {
    emsg.InitErrno("Rw11VirtTermTcp::Open","socket() failed: ", errno);
    emsg.InitErrno("Rw11VirtTermTcp::Open","socket() failed: ", errno);
    return false;
    return false;
  }
  }
 
 
  int on = 1;
  int on = 1;
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
    emsg.InitErrno("Rw11VirtTermTcp::Open","setsockop() failed: ", errno);
    emsg.InitErrno("Rw11VirtTermTcp::Open","setsockop() failed: ", errno);
    close(fd);
    close(fd);
    return false;
    return false;
  }
  }
 
 
  sockaddr_in sa;
  sockaddr_in sa;
  memset(&sa, 0, sizeof(sa));
  memset(&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_family = AF_INET;
  sa.sin_port   = htons((unsigned short) portno);
  sa.sin_port   = htons((unsigned short) portno);
  sa.sin_addr.s_addr = htonl(INADDR_ANY);
  sa.sin_addr.s_addr = htonl(INADDR_ANY);
 
 
  // Note: ::bind needed below to avoid collision with std::bind... 
  // Note: ::bind needed below to avoid collision with std::bind... 
  if (::bind(fd, (sockaddr*) &sa, sizeof(sa)) < 0) {
  if (::bind(fd, (sockaddr*) &sa, sizeof(sa)) < 0) {
    emsg.InitErrno("Rw11VirtTermTcp::Open","bind() failed: ", errno);
    emsg.InitErrno("Rw11VirtTermTcp::Open","bind() failed: ", errno);
    close(fd);
    close(fd);
    return false;
    return false;
  }
  }
 
 
  if (listen(fd, 1) <0) {
  if (listen(fd, 1) <0) {
    emsg.InitErrno("Rw11VirtTermTcp::Open","listen() failed: ", errno);
    emsg.InitErrno("Rw11VirtTermTcp::Open","listen() failed: ", errno);
    close(fd);
    close(fd);
    return false;
    return false;
  }
  }
 
 
  fFdListen = fd;
  fFdListen = fd;
  fChannelId = port;
  fChannelId = port;
  fState = ts_Listen;
  fState = ts_Listen;
 
 
  if (fTcpTrace) {
  if (fTcpTrace) {
    RlogMsg lmsg(LogFile(),'I');
    RlogMsg lmsg(LogFile(),'I');
    lmsg << "TermTcp: listen on " << fChannelId << " for " << Unit().Name();
    lmsg << "TermTcp: listen on " << fChannelId << " for " << Unit().Name();
  }
  }
 
 
  Server().AddPollHandler(boost::bind(&Rw11VirtTermTcp::ListenPollHandler,
  Server().AddPollHandler(boost::bind(&Rw11VirtTermTcp::ListenPollHandler,
                                      this, _1),
                                      this, _1),
                          fFdListen, POLLIN);
                          fFdListen, POLLIN);
 
 
  return true;
  return true;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! FIXME_docs
 
 
bool Rw11VirtTermTcp::Snd(const uint8_t* data, size_t count, RerrMsg& emsg)
bool Rw11VirtTermTcp::Snd(const uint8_t* data, size_t count, RerrMsg& emsg)
{
{
  fStats.Inc(kStatNVTSnd);
  fStats.Inc(kStatNVTSnd);
  const uint8_t* pdata = data;
  const uint8_t* pdata = data;
  const uint8_t* pdataend = data+count;
  const uint8_t* pdataend = data+count;
  if (count == 0) return true;              // quit if nothing to do
  if (count == 0) return true;              // quit if nothing to do
 
 
  if (!Connected()) {                       // if not connected keep last chars
  if (!Connected()) {                       // if not connected keep last chars
    for (size_t i=0; i<count; i++) fSndPreConQue.push_back(data[i]);
    for (size_t i=0; i<count; i++) fSndPreConQue.push_back(data[i]);
    fStats.Inc(kStatNVTPreConSave, double(count));
    fStats.Inc(kStatNVTPreConSave, double(count));
    while (fSndPreConQue.size() > kPreConQue_limit) {
    while (fSndPreConQue.size() > kPreConQue_limit) {
      fSndPreConQue.pop_front();
      fSndPreConQue.pop_front();
      fStats.Inc(kStatNVTPreConDrop);
      fStats.Inc(kStatNVTPreConDrop);
    }
    }
    return true;
    return true;
  }
  }
 
 
  uint8_t  obuf[1024];
  uint8_t  obuf[1024];
  while (pdata < pdataend) {
  while (pdata < pdataend) {
    uint8_t* pobuf = obuf;
    uint8_t* pobuf = obuf;
    uint8_t* pobufend = obuf+1024;
    uint8_t* pobufend = obuf+1024;
    while (pdata < pdataend && pobuf < pobufend-1) {
    while (pdata < pdataend && pobuf < pobufend-1) {
      if (*pdata == kCode_IAC) *pobuf++ = kCode_IAC;
      if (*pdata == kCode_IAC) *pobuf++ = kCode_IAC;
      *pobuf++ = *pdata++;
      *pobuf++ = *pdata++;
    }
    }
 
 
    int irc = write(fFd, obuf, pobuf-obuf);
    int irc = write(fFd, obuf, pobuf-obuf);
    if (irc < 0) {
    if (irc < 0) {
      RlogMsg lmsg(LogFile(),'E');
      RlogMsg lmsg(LogFile(),'E');
      RerrMsg emsg("Rw11VirtTermTcp::Snd",
      RerrMsg emsg("Rw11VirtTermTcp::Snd",
                   string("write() for port ") + fChannelId + " failed: ",
                   string("write() for port ") + fChannelId + " failed: ",
                   errno);
                   errno);
      lmsg << emsg;
      lmsg << emsg;
    } else {
    } else {
      fStats.Inc(kStatNVTSndRaw, double(irc));
      fStats.Inc(kStatNVTSndRaw, double(irc));
    }
    }
  }
  }
 
 
  fStats.Inc(kStatNVTSndByt, double(count));
  fStats.Inc(kStatNVTSndByt, double(count));
  return true;
  return true;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! FIXME_docs
 
 
void Rw11VirtTermTcp::Dump(std::ostream& os, int ind, const char* text) const
void Rw11VirtTermTcp::Dump(std::ostream& os, int ind, const char* text) const
{
{
  RosFill bl(ind);
  RosFill bl(ind);
  os << bl << (text?text:"--") << "Rw11VirtTermTcp @ " << this << endl;
  os << bl << (text?text:"--") << "Rw11VirtTermTcp @ " << this << endl;
 
 
  os << bl << "  fFdListen:       " << fFdListen << endl;
  os << bl << "  fFdListen:       " << fFdListen << endl;
  os << bl << "  fFd:             " << fFd << endl;
  os << bl << "  fFd:             " << fFd << endl;
  const char* t_state = "";
  const char* t_state = "";
  switch (fState) {
  switch (fState) {
  case ts_Closed: t_state = "ts_Closed";  break;
  case ts_Closed: t_state = "ts_Closed";  break;
  case ts_Listen: t_state = "ts_Listen";  break;
  case ts_Listen: t_state = "ts_Listen";  break;
  case ts_Stream: t_state = "ts_Stream";  break;
  case ts_Stream: t_state = "ts_Stream";  break;
  case ts_Iac:    t_state = "ts_Iac";     break;
  case ts_Iac:    t_state = "ts_Iac";     break;
  case ts_Cmd:    t_state = "ts_Cmd";     break;
  case ts_Cmd:    t_state = "ts_Cmd";     break;
  case ts_Subneg: t_state = "ts_Subneg";  break;
  case ts_Subneg: t_state = "ts_Subneg";  break;
  case ts_Subiac: t_state = "ts_Subiac";  break;
  case ts_Subiac: t_state = "ts_Subiac";  break;
  default: t_state = "???";
  default: t_state = "???";
  }
  }
  os << bl << "  fState:          " << t_state    << endl;
  os << bl << "  fState:          " << t_state    << endl;
  os << bl << "  fTcpTrace:       " << fTcpTrace  << endl;
  os << bl << "  fTcpTrace:       " << fTcpTrace  << endl;
  os << bl << "  fSndPreConQue.size" << fSndPreConQue.size()  << endl;
  os << bl << "  fSndPreConQue.size" << fSndPreConQue.size()  << endl;
  Rw11VirtTerm::Dump(os, ind, " ^");
  Rw11VirtTerm::Dump(os, ind, " ^");
  return;
  return;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! FIXME_docs
 
 
int Rw11VirtTermTcp::ListenPollHandler(const pollfd& pfd)
int Rw11VirtTermTcp::ListenPollHandler(const pollfd& pfd)
{
{
  // bail-out and cancel handler if poll returns an error event
  // bail-out and cancel handler if poll returns an error event
  if (pfd.revents & (~pfd.events)) return -1;
  if (pfd.revents & (~pfd.events)) return -1;
 
 
  fFd = accept(fFdListen, NULL, 0);
  fFd = accept(fFdListen, NULL, 0);
 
 
  if (fFd < 0) {
  if (fFd < 0) {
    RlogMsg lmsg(LogFile(),'E');
    RlogMsg lmsg(LogFile(),'E');
    RerrMsg emsg("Rw11VirtTermTcp::ListenPollHandler",
    RerrMsg emsg("Rw11VirtTermTcp::ListenPollHandler",
                 string("accept() for port ") + fChannelId + " failed: ",
                 string("accept() for port ") + fChannelId + " failed: ",
                 errno);
                 errno);
    lmsg << emsg;
    lmsg << emsg;
    // FIXME_code: proper error handling
    // FIXME_code: proper error handling
    return 0;
    return 0;
  }
  }
 
 
  fStats.Inc(kStatNVTAccept);
  fStats.Inc(kStatNVTAccept);
 
 
  uint8_t buf_1[3] = {kCode_IAC, kCode_WILL, kOpt_LINE};
  uint8_t buf_1[3] = {kCode_IAC, kCode_WILL, kOpt_LINE};
  uint8_t buf_2[3] = {kCode_IAC, kCode_WILL, kOpt_SGA};
  uint8_t buf_2[3] = {kCode_IAC, kCode_WILL, kOpt_SGA};
  uint8_t buf_3[3] = {kCode_IAC, kCode_WILL, kOpt_ECHO};
  uint8_t buf_3[3] = {kCode_IAC, kCode_WILL, kOpt_ECHO};
  uint8_t buf_4[3] = {kCode_IAC, kCode_WILL, kOpt_BIN};
  uint8_t buf_4[3] = {kCode_IAC, kCode_WILL, kOpt_BIN};
  uint8_t buf_5[3] = {kCode_IAC, kCode_DO  , kOpt_BIN};
  uint8_t buf_5[3] = {kCode_IAC, kCode_DO  , kOpt_BIN};
 
 
  int nerr = 0;
  int nerr = 0;
 
 
  // send initial negotiation WILLs and DOs
  // send initial negotiation WILLs and DOs
  if (write(fFd, buf_1, sizeof(buf_1)) < 0) nerr += 1;
  if (write(fFd, buf_1, sizeof(buf_1)) < 0) nerr += 1;
  if (write(fFd, buf_2, sizeof(buf_2)) < 0) nerr += 1;
  if (write(fFd, buf_2, sizeof(buf_2)) < 0) nerr += 1;
  if (write(fFd, buf_3, sizeof(buf_3)) < 0) nerr += 1;
  if (write(fFd, buf_3, sizeof(buf_3)) < 0) nerr += 1;
  if (write(fFd, buf_4, sizeof(buf_4)) < 0) nerr += 1;
  if (write(fFd, buf_4, sizeof(buf_4)) < 0) nerr += 1;
  if (write(fFd, buf_5, sizeof(buf_5)) < 0) nerr += 1;
  if (write(fFd, buf_5, sizeof(buf_5)) < 0) nerr += 1;
 
 
  // send connect message
  // send connect message
  if (nerr==0) {
  if (nerr==0) {
    stringstream msg;
    stringstream msg;
    msg << "\r\nconnect on port " << fChannelId
    msg << "\r\nconnect on port " << fChannelId
        << " for " << Unit().Name() << "\r\n\r\n";
        << " for " << Unit().Name() << "\r\n\r\n";
    string str = msg.str();
    string str = msg.str();
    if (write(fFd, str.c_str(), str.length()) < 0) nerr += 1;
    if (write(fFd, str.c_str(), str.length()) < 0) nerr += 1;
  }
  }
 
 
  // send chars buffered while attached but not connected
  // send chars buffered while attached but not connected
  if (nerr==0 && fSndPreConQue.size()) {
  if (nerr==0 && fSndPreConQue.size()) {
    stringstream msg;
    stringstream msg;
    while (!fSndPreConQue.empty()) {
    while (!fSndPreConQue.empty()) {
      msg << char(fSndPreConQue.front());
      msg << char(fSndPreConQue.front());
      fSndPreConQue.pop_front();
      fSndPreConQue.pop_front();
    }
    }
    string str = msg.str();
    string str = msg.str();
    if (write(fFd, str.c_str(), str.length()) < 0) nerr += 1;
    if (write(fFd, str.c_str(), str.length()) < 0) nerr += 1;
  }
  }
 
 
  if (nerr) {
  if (nerr) {
    close(fFd);
    close(fFd);
    fFd = -1;
    fFd = -1;
    RlogMsg lmsg(LogFile(),'E');
    RlogMsg lmsg(LogFile(),'E');
    RerrMsg emsg("Rw11VirtTermTcp::ListenPollHandler",
    RerrMsg emsg("Rw11VirtTermTcp::ListenPollHandler",
                 string("initial write()s for port ") + fChannelId +
                 string("initial write()s for port ") + fChannelId +
                 " failed: ", errno);
                 " failed: ", errno);
    lmsg << emsg;
    lmsg << emsg;
    return 0;
    return 0;
  }
  }
 
 
  if (fTcpTrace) {
  if (fTcpTrace) {
    RlogMsg lmsg(LogFile(),'I');
    RlogMsg lmsg(LogFile(),'I');
    lmsg << "TermTcp: accept on " << fChannelId << " for " << Unit().Name();
    lmsg << "TermTcp: accept on " << fChannelId << " for " << Unit().Name();
  }
  }
 
 
  fState = ts_Stream;
  fState = ts_Stream;
 
 
  Server().RemovePollHandler(fFdListen);
  Server().RemovePollHandler(fFdListen);
  Server().AddPollHandler(boost::bind(&Rw11VirtTermTcp::RcvPollHandler,
  Server().AddPollHandler(boost::bind(&Rw11VirtTermTcp::RcvPollHandler,
                                      this, _1),
                                      this, _1),
                          fFd, POLLIN);
                          fFd, POLLIN);
  return 0;
  return 0;
}
}
 
 
//------------------------------------------+-----------------------------------
//------------------------------------------+-----------------------------------
//! FIXME_docs
//! FIXME_docs
 
 
int Rw11VirtTermTcp::RcvPollHandler(const pollfd& pfd)
int Rw11VirtTermTcp::RcvPollHandler(const pollfd& pfd)
{
{
  fStats.Inc(kStatNVTRcvPoll);
  fStats.Inc(kStatNVTRcvPoll);
 
 
  int irc = -1;
  int irc = -1;
 
 
  if (pfd.revents & POLLIN) {
  if (pfd.revents & POLLIN) {
    uint8_t ibuf[1024];
    uint8_t ibuf[1024];
    uint8_t obuf[1024];
    uint8_t obuf[1024];
    uint8_t* pobuf = obuf;
    uint8_t* pobuf = obuf;
 
 
    irc = read(fFd, ibuf, 1024);
    irc = read(fFd, ibuf, 1024);
 
 
    if (irc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return 0;
    if (irc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return 0;
 
 
    if (irc > 0) {
    if (irc > 0) {
      fStats.Inc(kStatNVTRcvRaw, double(irc));
      fStats.Inc(kStatNVTRcvRaw, double(irc));
      for (int i=0; i<irc; i++) {
      for (int i=0; i<irc; i++) {
        uint8_t byt = ibuf[i];
        uint8_t byt = ibuf[i];
        switch (fState) {
        switch (fState) {
        case ts_Stream:
        case ts_Stream:
          if (byt == kCode_IAC) {
          if (byt == kCode_IAC) {
            fState = ts_Iac;
            fState = ts_Iac;
          } else {
          } else {
            *pobuf++ = byt;
            *pobuf++ = byt;
            fStats.Inc(kStatNVTRcvByt, 1.);
            fStats.Inc(kStatNVTRcvByt, 1.);
          }
          }
          break;
          break;
 
 
        case ts_Iac:
        case ts_Iac:
          if (byt == kCode_WILL || byt == kCode_WONT ||
          if (byt == kCode_WILL || byt == kCode_WONT ||
              byt == kCode_DO   || byt == kCode_DONT) {
              byt == kCode_DO   || byt == kCode_DONT) {
            fState = ts_Cmd;
            fState = ts_Cmd;
          } else if (byt == kCode_SB) {
          } else if (byt == kCode_SB) {
            fState = ts_Subneg;
            fState = ts_Subneg;
          } else {
          } else {
            fState = ts_Stream;
            fState = ts_Stream;
          }
          }
          break;
          break;
 
 
        case ts_Cmd:
        case ts_Cmd:
          fState = ts_Stream;
          fState = ts_Stream;
          break;
          break;
 
 
        case ts_Subneg:
        case ts_Subneg:
          if (byt == kCode_IAC) {
          if (byt == kCode_IAC) {
            fState = ts_Subiac;
            fState = ts_Subiac;
          }
          }
          break;
          break;
 
 
        case ts_Subiac:
        case ts_Subiac:
          fState = ts_Stream;
          fState = ts_Stream;
          break;
          break;
        default:
        default:
          break;
          break;
        }
        }
 
 
      }
      }
    }
    }
 
 
    if (pobuf > obuf) fRcvCb(obuf, pobuf - obuf);
    if (pobuf > obuf) fRcvCb(obuf, pobuf - obuf);
  }
  }
 
 
 
 
  if (irc <= 0) {
  if (irc <= 0) {
    if (irc < 0) {
    if (irc < 0) {
      RlogMsg lmsg(LogFile(),'E');
      RlogMsg lmsg(LogFile(),'E');
      RerrMsg emsg("Rw11VirtTermTcp::ListenPollHandler",
      RerrMsg emsg("Rw11VirtTermTcp::ListenPollHandler",
                   string("read() for port ") + fChannelId + " failed: ",
                   string("read() for port ") + fChannelId + " failed: ",
                   errno);
                   errno);
      lmsg << emsg;
      lmsg << emsg;
    }
    }
    if (fTcpTrace) {
    if (fTcpTrace) {
      RlogMsg lmsg(LogFile(),'I');
      RlogMsg lmsg(LogFile(),'I');
      lmsg << "TermTcp: close on " << fChannelId << " for " << Unit().Name();
      lmsg << "TermTcp: close on " << fChannelId << " for " << Unit().Name();
    }
    }
    close(fFd);
    close(fFd);
    fFd = -1;
    fFd = -1;
    Server().AddPollHandler(boost::bind(&Rw11VirtTermTcp::ListenPollHandler,
    Server().AddPollHandler(boost::bind(&Rw11VirtTermTcp::ListenPollHandler,
                                        this, _1),
                                        this, _1),
                            fFdListen, POLLIN);
                            fFdListen, POLLIN);
    fState = ts_Listen;
    fState = ts_Listen;
    return -1;
    return -1;
  }
  }
 
 
  return 0;
  return 0;
}
}
 
 
 
 
} // end namespace Retro
} // end namespace Retro
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.