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 19

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

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

powered by: WebSVN 2.1.0

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