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

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.6/] [tools/] [src/] [librw11/] [Rw11VirtTermTcp.cpp] - Blame information for rev 20

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 20 wfjm
// $Id: Rw11VirtTermTcp.cpp 508 2013-04-20 18:43:28Z mueller $
2 19 wfjm
//
3
// Copyright 2013- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4
//
5
// This program is free software; you may redistribute and/or modify it under
6
// the terms of the GNU General Public License as published by the Free
7
// Software Foundation, either version 2, or at your option any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
11
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
// for complete details.
13
// 
14
// Revision History: 
15
// Date         Rev Version  Comment
16 20 wfjm
// 2013-04-20   508   1.0.1  add fSndPreConQue handling
17 19 wfjm
// 2013-03-06   495   1.0    Initial version
18
// 2013-02-13   488   0.1    First draft
19
// ---------------------------------------------------------------------------
20
 
21
/*!
22
  \file
23 20 wfjm
  \version $Id: Rw11VirtTermTcp.cpp 508 2013-04-20 18:43:28Z mueller $
24 19 wfjm
  \brief   Implemenation of Rw11VirtTermTcp.
25
*/
26
 
27
#include <stdlib.h>
28
#include <sys/types.h>
29
#include <sys/socket.h>
30
#include <netdb.h>
31
#include <string.h>
32
 
33
#include <sstream>
34
 
35
#include "librtools/RosFill.hpp"
36
#include "librtools/RlogMsg.hpp"
37
 
38
#include "Rw11VirtTermTcp.hpp"
39
 
40
using namespace std;
41
 
42
/*!
43
  \class Retro::Rw11VirtTermTcp
44
  \brief FIXME_docs
45
*/
46
 
47
// all method definitions in namespace Retro
48
namespace Retro {
49
 
50
//------------------------------------------+-----------------------------------
51
// constants definitions
52
 
53
const uint8_t  Rw11VirtTermTcp::kCode_NULL;
54
const uint8_t  Rw11VirtTermTcp::kCode_LF;
55
const uint8_t  Rw11VirtTermTcp::kCode_CR;
56
const uint8_t  Rw11VirtTermTcp::kCode_ESC;
57
const uint8_t  Rw11VirtTermTcp::kCode_SE;
58
const uint8_t  Rw11VirtTermTcp::kCode_NOP;
59
const uint8_t  Rw11VirtTermTcp::kCode_IP;
60
const uint8_t  Rw11VirtTermTcp::kCode_GA;
61
const uint8_t  Rw11VirtTermTcp::kCode_SB;
62
const uint8_t  Rw11VirtTermTcp::kCode_WILL;
63
const uint8_t  Rw11VirtTermTcp::kCode_WONT;
64
const uint8_t  Rw11VirtTermTcp::kCode_DO;
65
const uint8_t  Rw11VirtTermTcp::kCode_DONT;
66
const uint8_t  Rw11VirtTermTcp::kCode_IAC;
67
 
68
const uint8_t  Rw11VirtTermTcp::kOpt_BIN;
69
const uint8_t  Rw11VirtTermTcp::kOpt_ECHO;
70
const uint8_t  Rw11VirtTermTcp::kOpt_SGA;
71
const uint8_t  Rw11VirtTermTcp::kOpt_TTYP;
72
const uint8_t  Rw11VirtTermTcp::kOpt_LINE;
73
 
74 20 wfjm
const size_t   Rw11VirtTermTcp::kPreConQue_limit;
75
 
76 19 wfjm
//------------------------------------------+-----------------------------------
77
//! Default constructor
78
 
79
Rw11VirtTermTcp::Rw11VirtTermTcp(Rw11Unit* punit)
80
  : Rw11VirtTerm(punit),
81
    fFdListen(-1),
82
    fFd(-1),
83
    fState(ts_Closed),
84 20 wfjm
    fTcpTrace(false),
85
    fSndPreConQue()
86 19 wfjm
{
87 20 wfjm
  fStats.Define(kStatNVTPreConSave , "NVTPreConSave" ,
88
                "VT snd bytes saved prior connect");
89
  fStats.Define(kStatNVTPreConDrop , "NVTPreConDrop" ,
90
                "VT snd bytes dropped prior connect");
91 19 wfjm
  fStats.Define(kStatNVTListenPoll , "NVTListenPoll" ,
92 20 wfjm
                "VT ListenPollHandler() calls");
93
  fStats.Define(kStatNVTAccept,      "NVTAccept",     "VT socket accepts");
94
  fStats.Define(kStatNVTRcvRaw,      "NVTRcvRaw",     "VT raw bytes received");
95
  fStats.Define(kStatNVTSndRaw,      "NVTSndRaw",     "VT raw bytes send");
96 19 wfjm
}
97
 
98
//------------------------------------------+-----------------------------------
99
//! Destructor
100
 
101
Rw11VirtTermTcp::~Rw11VirtTermTcp()
102
{
103
  if (fFdListen > 2) {
104
    Server().RemovePollHandler(fFdListen);
105
    close(fFdListen);
106
  }
107 20 wfjm
  if (Connected()) {
108 19 wfjm
    Server().RemovePollHandler(fFd);
109
    close(fFd);
110
  }
111
}
112
 
113
//------------------------------------------+-----------------------------------
114
//! FIXME_docs
115
 
116
bool Rw11VirtTermTcp::Open(const std::string& url, RerrMsg& emsg)
117
{
118
  if (!fUrl.Set(url, "|port=|trace|", emsg)) return false;
119
  if (!(fUrl.FindOpt("port"))) {
120
    emsg.Init("Rw11VirtTermTcp::Open", "port= option not specified");
121
    return false;
122
  }
123
 
124
  fTcpTrace = fUrl.FindOpt("trace");
125
 
126
  string port;
127
  fUrl.FindOpt("port",port);
128
  int portno = atoi(port.c_str());
129
  // FIXME_code: error handling ...
130
 
131
  protoent* pe = getprotobyname("tcp");
132
  if (pe == 0) {
133
    emsg.Init("Rw11VirtTermTcp::Open","getprotobyname(\"tcp\") failed");
134
    return false;
135
  }
136
 
137
  int fd = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, pe->p_proto);
138
  if (fd < 0) {
139
    emsg.InitErrno("Rw11VirtTermTcp::Open","socket() failed: ", errno);
140
    return false;
141
  }
142
 
143
  int on = 1;
144
  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
145
    emsg.InitErrno("Rw11VirtTermTcp::Open","setsockop() failed: ", errno);
146
    close(fd);
147
    return false;
148
  }
149
 
150
  sockaddr_in sa;
151
  memset(&sa, 0, sizeof(sa));
152
  sa.sin_family = AF_INET;
153
  sa.sin_port   = htons((unsigned short) portno);
154
  sa.sin_addr.s_addr = htonl(INADDR_ANY);
155
 
156
  // Note: ::bind needed below to avoid collision with std::bind... 
157
  if (::bind(fd, (sockaddr*) &sa, sizeof(sa)) < 0) {
158
    emsg.InitErrno("Rw11VirtTermTcp::Open","bind() failed: ", errno);
159
    close(fd);
160
    return false;
161
  }
162
 
163
  if (listen(fd, 1) <0) {
164
    emsg.InitErrno("Rw11VirtTermTcp::Open","listen() failed: ", errno);
165
    close(fd);
166
    return false;
167
  }
168
 
169
  fFdListen = fd;
170
  fChannelId = port;
171
  fState = ts_Listen;
172
 
173
  if (fTcpTrace) {
174
    RlogMsg lmsg(LogFile(),'I');
175
    lmsg << "TermTcp: listen on " << fChannelId << " for " << Unit().Name();
176
  }
177
 
178
  Server().AddPollHandler(boost::bind(&Rw11VirtTermTcp::ListenPollHandler,
179
                                      this, _1),
180
                          fFdListen, POLLIN);
181
 
182
  return true;
183
}
184
 
185
//------------------------------------------+-----------------------------------
186
//! FIXME_docs
187
 
188
bool Rw11VirtTermTcp::Snd(const uint8_t* data, size_t count, RerrMsg& emsg)
189
{
190
  fStats.Inc(kStatNVTSnd);
191
  const uint8_t* pdata = data;
192
  const uint8_t* pdataend = data+count;
193 20 wfjm
  if (count == 0) return true;              // quit if nothing to do
194 19 wfjm
 
195 20 wfjm
  if (!Connected()) {                       // if not connected keep last chars
196
    for (size_t i=0; i<count; i++) fSndPreConQue.push_back(data[i]);
197
    fStats.Inc(kStatNVTPreConSave, double(count));
198
    while (fSndPreConQue.size() > kPreConQue_limit) {
199
      fSndPreConQue.pop_front();
200
      fStats.Inc(kStatNVTPreConDrop);
201
    }
202
    return true;
203
  }
204
 
205 19 wfjm
  uint8_t  obuf[1024];
206
  while (pdata < pdataend) {
207
    uint8_t* pobuf = obuf;
208
    uint8_t* pobufend = obuf+1024;
209
    while (pdata < pdataend && pobuf < pobufend-1) {
210
      if (*pdata == kCode_IAC) *pobuf++ = kCode_IAC;
211
      *pobuf++ = *pdata++;
212
    }
213
 
214
    int irc = write(fFd, obuf, pobuf-obuf);
215
    if (irc < 0) {
216
      RlogMsg lmsg(LogFile(),'E');
217
      RerrMsg emsg("Rw11VirtTermTcp::Snd",
218
                   string("write() for port ") + fChannelId +
219
                   string(" failed: ", errno));
220
      lmsg << emsg;
221
    } else {
222
      fStats.Inc(kStatNVTSndRaw, double(irc));
223
    }
224
  }
225
 
226
  fStats.Inc(kStatNVTSndByt, double(count));
227
  return true;
228
}
229
 
230
//------------------------------------------+-----------------------------------
231
//! FIXME_docs
232
 
233
void Rw11VirtTermTcp::Dump(std::ostream& os, int ind, const char* text) const
234
{
235
  RosFill bl(ind);
236
  os << bl << (text?text:"--") << "Rw11VirtTermTcp @ " << this << endl;
237
 
238
  os << bl << "  fFdListen:       " << fFdListen << endl;
239
  os << bl << "  fFd:             " << fFd << endl;
240
  const char* t_state = "";
241
  switch (fState) {
242
  case ts_Closed: t_state = "ts_Closed";  break;
243
  case ts_Listen: t_state = "ts_Listen";  break;
244
  case ts_Stream: t_state = "ts_Stream";  break;
245
  case ts_Iac:    t_state = "ts_Iac";     break;
246
  case ts_Cmd:    t_state = "ts_Cmd";     break;
247
  case ts_Subneg: t_state = "ts_Subneg";  break;
248
  case ts_Subiac: t_state = "ts_Subiac";  break;
249
  default: t_state = "???";
250
  }
251
  os << bl << "  fState:          " << t_state    << endl;
252
  os << bl << "  fTcpTrace:       " << fTcpTrace  << endl;
253 20 wfjm
  os << bl << "  fSndPreConQue.size" << fSndPreConQue.size()  << endl;
254 19 wfjm
  Rw11VirtTerm::Dump(os, ind, " ^");
255
  return;
256
}
257
 
258
//------------------------------------------+-----------------------------------
259
//! FIXME_docs
260
 
261
int Rw11VirtTermTcp::ListenPollHandler(const pollfd& pfd)
262
{
263
  // bail-out and cancel handler if poll returns an error event
264
  if (pfd.revents & (~pfd.events)) return -1;
265
 
266
  fFd = accept(fFdListen, NULL, 0);
267
 
268
  if (fFd < 0) {
269
    RlogMsg lmsg(LogFile(),'E');
270
    RerrMsg emsg("Rw11VirtTermTcp::ListenPollHandler",
271
                 string("accept() for port ") + fChannelId +
272
                 string(" failed: ", errno));
273
    lmsg << emsg;
274
    // FIXME_code: proper error handling
275
    return 0;
276
  }
277
 
278
  fStats.Inc(kStatNVTAccept);
279
 
280
  uint8_t buf_1[3] = {kCode_IAC, kCode_WILL, kOpt_LINE};
281
  uint8_t buf_2[3] = {kCode_IAC, kCode_WILL, kOpt_SGA};
282
  uint8_t buf_3[3] = {kCode_IAC, kCode_WILL, kOpt_ECHO};
283
  uint8_t buf_4[3] = {kCode_IAC, kCode_WILL, kOpt_BIN};
284
  uint8_t buf_5[3] = {kCode_IAC, kCode_DO  , kOpt_BIN};
285
 
286
  int nerr = 0;
287
 
288 20 wfjm
  // send initial negotiation WILLs and DOs
289 19 wfjm
  if (write(fFd, buf_1, sizeof(buf_1)) < 0) nerr += 1;
290
  if (write(fFd, buf_2, sizeof(buf_2)) < 0) nerr += 1;
291
  if (write(fFd, buf_3, sizeof(buf_3)) < 0) nerr += 1;
292
  if (write(fFd, buf_4, sizeof(buf_4)) < 0) nerr += 1;
293
  if (write(fFd, buf_5, sizeof(buf_5)) < 0) nerr += 1;
294 20 wfjm
 
295
  // send connect message
296 19 wfjm
  if (nerr==0) {
297
    stringstream msg;
298
    msg << "\r\nconnect on port " << fChannelId
299
        << " for " << Unit().Name() << "\r\n\r\n";
300
    string str = msg.str();
301
    if (write(fFd, str.c_str(), str.length()) < 0) nerr += 1;
302
  }
303
 
304 20 wfjm
  // send chars buffered while attached but not connected
305
  if (nerr==0 && fSndPreConQue.size()) {
306
    stringstream msg;
307
    while (!fSndPreConQue.empty()) {
308
      msg << char(fSndPreConQue.front());
309
      fSndPreConQue.pop_front();
310
    }
311
    string str = msg.str();
312
    if (write(fFd, str.c_str(), str.length()) < 0) nerr += 1;
313
  }
314
 
315 19 wfjm
  if (nerr) {
316
    close(fFd);
317
    fFd = -1;
318
    RlogMsg lmsg(LogFile(),'E');
319
    RerrMsg emsg("Rw11VirtTermTcp::ListenPollHandler",
320
                 string("initial write()s for port ") + fChannelId +
321
                 string(" failed: ", errno));
322
    lmsg << emsg;
323
    return 0;
324
  }
325
 
326
  if (fTcpTrace) {
327
    RlogMsg lmsg(LogFile(),'I');
328
    lmsg << "TermTcp: accept on " << fChannelId << " for " << Unit().Name();
329
  }
330
 
331
  fState = ts_Stream;
332
 
333
  Server().RemovePollHandler(fFdListen);
334
  Server().AddPollHandler(boost::bind(&Rw11VirtTermTcp::RcvPollHandler,
335
                                      this, _1),
336
                          fFd, POLLIN);
337
  return 0;
338
}
339
 
340
//------------------------------------------+-----------------------------------
341
//! FIXME_docs
342
 
343
int Rw11VirtTermTcp::RcvPollHandler(const pollfd& pfd)
344
{
345
  fStats.Inc(kStatNVTRcvPoll);
346
 
347
  int irc = -1;
348
 
349
  if (pfd.revents & POLLIN) {
350
    uint8_t ibuf[1024];
351
    uint8_t obuf[1024];
352
    uint8_t* pobuf = obuf;
353
 
354
    irc = read(fFd, ibuf, 1024);
355
 
356
    if (irc < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return 0;
357
 
358
    if (irc > 0) {
359
      fStats.Inc(kStatNVTRcvRaw, double(irc));
360
      for (int i=0; i<irc; i++) {
361
        uint8_t byt = ibuf[i];
362
        switch (fState) {
363
        case ts_Stream:
364
          if (byt == kCode_IAC) {
365
            fState = ts_Iac;
366
          } else {
367
            *pobuf++ = byt;
368
            fStats.Inc(kStatNVTRcvByt, 1.);
369
          }
370
          break;
371
 
372
        case ts_Iac:
373
          if (byt == kCode_WILL || byt == kCode_WONT ||
374
              byt == kCode_DO   || byt == kCode_DONT) {
375
            fState = ts_Cmd;
376
          } else if (byt == kCode_SB) {
377
            fState = ts_Subneg;
378
          } else {
379
            fState = ts_Stream;
380
          }
381
          break;
382
 
383
        case ts_Cmd:
384
          fState = ts_Stream;
385
          break;
386
 
387
        case ts_Subneg:
388
          if (byt == kCode_IAC) {
389
            fState = ts_Subiac;
390
          }
391
          break;
392
 
393
        case ts_Subiac:
394
          fState = ts_Stream;
395
          break;
396
        default:
397
          break;
398
        }
399
 
400
      }
401
    }
402
 
403
    if (pobuf > obuf) fRcvCb(obuf, pobuf - obuf);
404
  }
405
 
406
 
407
  if (irc <= 0) {
408
    if (irc < 0) {
409
      RlogMsg lmsg(LogFile(),'E');
410
      RerrMsg emsg("Rw11VirtTermTcp::ListenPollHandler",
411
                   string("read() for port ") + fChannelId +
412
                   string(" failed: ", errno));
413
      lmsg << emsg;
414
    }
415
    if (fTcpTrace) {
416
      RlogMsg lmsg(LogFile(),'I');
417
      lmsg << "TermTcp: close on " << fChannelId << " for " << Unit().Name();
418
    }
419
    close(fFd);
420
    fFd = -1;
421
    Server().AddPollHandler(boost::bind(&Rw11VirtTermTcp::ListenPollHandler,
422
                                        this, _1),
423
                            fFdListen, POLLIN);
424
    fState = ts_Listen;
425
    return -1;
426
  }
427
 
428
  return 0;
429
}
430
 
431
 
432
} // end namespace Retro

powered by: WebSVN 2.1.0

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