From 6ab1aa5f2156ef781da6e1b57a183825b88bef9a Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Tue, 29 Jun 1999 02:23:31 +0000 Subject: Initial import --- ncpd/Makefile.am | 8 ++ ncpd/channel.cc | 60 +++++++++++ ncpd/channel.h | 34 +++++++ ncpd/link.cc | 166 ++++++++++++++++++++++++++++++ ncpd/link.h | 34 +++++++ ncpd/linkchan.cc | 54 ++++++++++ ncpd/linkchan.h | 16 +++ ncpd/main.cc | 157 ++++++++++++++++++++++++++++ ncpd/mp_serial.c | 191 +++++++++++++++++++++++++++++++++++ ncpd/mp_serial.h | 7 ++ ncpd/ncp.cc | 292 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ncpd/ncp.h | 49 +++++++++ ncpd/packet.cc | 226 +++++++++++++++++++++++++++++++++++++++++ ncpd/packet.h | 43 ++++++++ ncpd/socketchan.cc | 105 +++++++++++++++++++ ncpd/socketchan.h | 28 +++++ 16 files changed, 1470 insertions(+) create mode 100644 ncpd/Makefile.am create mode 100644 ncpd/channel.cc create mode 100644 ncpd/channel.h create mode 100644 ncpd/link.cc create mode 100644 ncpd/link.h create mode 100644 ncpd/linkchan.cc create mode 100644 ncpd/linkchan.h create mode 100644 ncpd/main.cc create mode 100644 ncpd/mp_serial.c create mode 100644 ncpd/mp_serial.h create mode 100644 ncpd/ncp.cc create mode 100644 ncpd/ncp.h create mode 100644 ncpd/packet.cc create mode 100644 ncpd/packet.h create mode 100644 ncpd/socketchan.cc create mode 100644 ncpd/socketchan.h (limited to 'ncpd') diff --git a/ncpd/Makefile.am b/ncpd/Makefile.am new file mode 100644 index 0000000..6ee7caf --- /dev/null +++ b/ncpd/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES=-I../lib + +LIBS = -L../lib -lutils + +sbin_PROGRAMS = ncpd + +ncpd_SOURCES = channel.cc link.cc linkchan.cc main.cc \ + ncp.cc packet.cc socketchan.cc mp_serial.c diff --git a/ncpd/channel.cc b/ncpd/channel.cc new file mode 100644 index 0000000..6cc3ff3 --- /dev/null +++ b/ncpd/channel.cc @@ -0,0 +1,60 @@ +// +// PLP - An implementation of the PSION link protocol +// +// Copyright (C) 1999 Philip Proudman +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// e-mail philip.proudman@btinternet.com + + +#include + +#include "bool.h" +#include "channel.h" +#include "ncp.h" + +channel::channel(ncp *_ncpController) { + ncpController = _ncpController; + _terminate = false; +} + +void channel::ncpSend(bufferStore &a) { + ncpController->send(ncpChannel, a); +} + +bool channel::terminate() { + return _terminate; +} + +void channel::terminateWhenAsked() { + _terminate = true; +} + +void channel::ncpConnect() { + ncpController->connect(this); +} + +void channel::ncpDisconnect() { + ncpController->disconnect(ncpChannel); +} + +void channel::setNcpChannel(int chan) { + ncpChannel = chan; +} + +void channel::newNcpController(ncp *_ncpController) { + ncpController = _ncpController; +} diff --git a/ncpd/channel.h b/ncpd/channel.h new file mode 100644 index 0000000..b71e248 --- /dev/null +++ b/ncpd/channel.h @@ -0,0 +1,34 @@ +#ifndef _channel_h_ +#define _channel_h_ + +#include + +#include "bool.h" + +class ncp; +class bufferStore; + +class channel { +public: + channel(ncp *ncpController); + void newNcpController(ncp *ncpController); + + void setNcpChannel(int chan); + void ncpSend(bufferStore &a); + virtual void ncpDataCallback(bufferStore &a) = NULL; + virtual const char *getNcpConnectName() = NULL; + void ncpConnect(); + virtual void ncpConnectAck() = NULL; + virtual void ncpConnectTerminate() = NULL; + void ncpDisconnect(); + + // The following two calls are used for destructing an instance + virtual bool terminate(); // Mainloop will terminate this class if true + void terminateWhenAsked(); +private: + ncp *ncpController; + bool _terminate; + int ncpChannel; +}; + +#endif diff --git a/ncpd/link.cc b/ncpd/link.cc new file mode 100644 index 0000000..f3a13df --- /dev/null +++ b/ncpd/link.cc @@ -0,0 +1,166 @@ +// +// PLP - An implementation of the PSION link protocol +// +// Copyright (C) 1999 Philip Proudman +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// e-mail philip.proudman@btinternet.com + +#include +#include +#include + +#include "defs.h" +#include "bool.h" +#include "link.h" +#include "packet.h" +#include "bufferstore.h" +#include "bufferarray.h" + +link::link(const char *fname, int baud, IOWatch & iow, bool _s5, bool _verbose): +s5(_s5) +{ + p = new packet(fname, baud, iow, PACKET_LAYER_DIAGNOSTICS); + verbose = _verbose; + idSent = 0; + idLastGot = -1; + newLink = true; + somethingToSend = false; + timesSent = 0; + failed = false; +} + +link::~link() +{ + delete p; +} + +void link:: +send(const bufferStore & buff) +{ + if (buff.getLen() > 300) + failed = true; + else + sendQueue.pushBuffer(buff); +} + +bufferArray link:: +poll() +{ + bufferArray ret; + bufferStore buff; + unsigned char type; + + while (p->get(type, buff)) { + if ((type & 0xf0) == 0x30) { + // Data + int ser = type & 0x0f; + if (verbose) + cout << "link: Got data ser " << ser << " : " << buff << endl; + // Send ack + if (idLastGot != ser) { + idLastGot = ser; + ret.pushBuffer(buff); + } else { + if (verbose) + cout << "link: Duplicated data - not passing back, repeating ack\n"; + } + if (verbose) + cout << "link: Send ack ser " << ser << endl; + bufferStore blank; + p->send(ser, blank); + break; + } else if ((type & 0xf0) == 0x00) { + // Ack + int ser = type & 0x0f; + if (ser == idSent) { + if (verbose) + cout << "link: Got ack " << ser << " : " << buff << endl; + somethingToSend = false; + timesSent = 0; + } + } else if ((type & 0xf0) == 0x20) { + // New link + int ser = type & 0x0f; + if (verbose) + cout << "link: got New link request " << ser << " : " << buff << endl; + idLastGot = 0; + bufferStore blank; + if (verbose) + cout << "link: Sending ack of new link\n"; + somethingToSend = false; + p->send(idLastGot, blank); + } else if ((type & 0xf0) == 0x10) { + // Disconnect + cerr << "Disconnect?\n"; + failed = true; + return ret; + } + } + + if (!somethingToSend) { + countToResend = 0; + if (newLink) { + somethingToSend = true; + toSend.init(); + newLink = false; + idSent = 0; + } else { + if (!sendQueue.empty()) { + somethingToSend = true; + toSend = sendQueue.popBuffer(); + idSent++; + if (idSent > 7) + idSent = 0; + } + } + } + if (somethingToSend) { + if (countToResend == 0) { + timesSent++; + if (timesSent == 5) { + failed = true; + } else { + if (toSend.empty()) { + // Request for new link + if (verbose) + cout << "link: Send req new session ser " << idSent << endl; + p->send(0x20 + idSent, toSend); + } else { + if (verbose) + cout << "link: Send data packet ser " << idSent << " : " << toSend << endl; + p->send(0x30 + idSent, toSend); + } + countToResend = 5; + } + } else { + countToResend--; + } + } + return ret; +} + +bool link:: +stuffToSend() +{ + return (somethingToSend || !sendQueue.empty()); +} + +bool link:: +hasFailed() +{ + return failed; +} diff --git a/ncpd/link.h b/ncpd/link.h new file mode 100644 index 0000000..f166513 --- /dev/null +++ b/ncpd/link.h @@ -0,0 +1,34 @@ +#ifndef _link_h_ +#define _link_h_ + +#include "bool.h" +#include "bufferstore.h" +#include "bufferarray.h" +class packet; +class IOWatch; + +class link { +public: + link(const char *fname, int baud, IOWatch &iow, bool s5, bool _verbose = false); + ~link(); + void send(const bufferStore &buff); + bufferArray poll(); + bool stuffToSend(); + bool hasFailed(); + +private: + packet *p; + int idSent; + int countToResend; + int timesSent; + bufferArray sendQueue; + bufferStore toSend; + int idLastGot; + bool newLink; + bool verbose; + bool somethingToSend; + bool failed; + bool s5; +}; + +#endif diff --git a/ncpd/linkchan.cc b/ncpd/linkchan.cc new file mode 100644 index 0000000..e5d7c13 --- /dev/null +++ b/ncpd/linkchan.cc @@ -0,0 +1,54 @@ +// +// PLP - An implementation of the PSION link protocol +// +// Copyright (C) 1999 Philip Proudman +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// e-mail philip.proudman@btinternet.com + +#include + +#include "linkchan.h" +#include "bufferstore.h" + +linkChan::linkChan(ncp * _ncpController):channel(_ncpController) +{ +} + +void linkChan:: +ncpDataCallback(bufferStore & a) +{ + cout << "linkchan: got message " << a << endl; +} + +const char *linkChan:: +getNcpConnectName() +{ + return "LINK.*"; +} + +void linkChan:: +ncpConnectAck() +{ + cout << "linkchan: got connect ack\n"; +} + +void linkChan:: +ncpConnectTerminate() +{ + cout << "linkchan: got connect terminate\n"; + terminateWhenAsked(); +} diff --git a/ncpd/linkchan.h b/ncpd/linkchan.h new file mode 100644 index 0000000..e90dee2 --- /dev/null +++ b/ncpd/linkchan.h @@ -0,0 +1,16 @@ +#ifndef _linkchan_h_ +#define _linkchan_h_ + +#include "channel.h" + +class linkChan : public channel { +public: + linkChan(ncp *ncpController); + + void ncpDataCallback(bufferStore &a); + const char *getNcpConnectName(); + void ncpConnectAck(); + void ncpConnectTerminate(); +}; + +#endif diff --git a/ncpd/main.cc b/ncpd/main.cc new file mode 100644 index 0000000..dd32729 --- /dev/null +++ b/ncpd/main.cc @@ -0,0 +1,157 @@ +// +// PLP - An implementation of the PSION link protocol +// +// Copyright (C) 1999 Philip Proudman +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// e-mail philip.proudman@btinternet.com + +#include +#include +#include +#include + +#include "defs.h" +#include "ncp.h" +#include "bufferstore.h" +#include "ppsocket.h" +#include "socketchan.h" +#include "iowatch.h" +#include "linkchan.h" + +void +checkForNewSocketConnection(ppsocket & skt, int &numScp, socketChan ** scp, ncp * a, IOWatch & iow) +{ + char peer[201]; + ppsocket *next = skt.accept(peer, 200); + if (next != NULL) { + // New connect + cout << "New socket connection from " << peer << endl; + if ((numScp == 7) || (!a->gotLinkChannel())) { + bufferStore a; + a.addStringT("No psion ncp channel free"); + next->sendBufferStore(a); + } else + scp[numScp++] = new socketChan(next, a, iow); + } +} + +void +pollSocketConnections(int &numScp, socketChan ** scp) +{ + for (int i = 0; i < numScp; i++) { + scp[i]->socketPoll(); + if (scp[i]->terminate()) { + // Requested channel termination + delete scp[i]; + numScp--; + for (int j = i; j < numScp; j++) + scp[j] = scp[j + 1]; + i--; + } + } +} + +void +resetSocketConnections(int &numScp, socketChan ** scp, ncp * a) +{ + for (int i = 0; i < numScp; i++) { + if (scp[i]->isConnected()) { + cout << "Killing\n"; + delete scp[i]; + numScp--; + for (int j = i; j < numScp; j++) + scp[j] = scp[j + 1]; + i--; + } else { + scp[i]->newNcpController(a); + if (scp[i]->getNcpConnectName() != NULL) { + cout << "Connecting\n"; + scp[i]->ncpConnect(); + } else + cout << "Ignoring\n"; + } + } +} + +void +usage() +{ + cout << "Version : " << VERSION << endl; + cout << "Usage : ncp [-s ] [-d ] [-b ]\n"; +} + +int +main(int argc, char **argv) +{ + ppsocket skt; + IOWatch iow; + skt.startup(); + + // Command line parameter processing + int sockNum = DPORT; + int baudRate = DSPEED; + const char *serialDevice = DDEV; + + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-s") && i + 1 < argc) { + sockNum = atoi(argv[++i]); + } else if (!strcmp(argv[i], "-d") && i + 1 < argc) { + serialDevice = argv[++i]; + } else if (!strcmp(argv[i], "-b") && i + 1 < argc) { + baudRate = atoi(argv[++i]); + } else { + usage(); + exit(1); + } + } + + if (!skt.listen("127.0.0.1", sockNum)) { + cerr << "Could not initiate listen on socket " << sockNum << endl; + cerr << "NCP is now started by rfsv - you don't have to do it explicitly yourself" << endl; + } else { + ncp *a = NULL; + int numScp; + socketChan *scp[8]; + + while (true) { + if (a == NULL) { + a = new ncp(serialDevice, baudRate, iow); + numScp = 0; + iow.addIO(skt.socket()); + } + // sockets + checkForNewSocketConnection(skt, numScp, scp, a, iow); + pollSocketConnections(numScp, scp); + + // psion + a->poll(); + + if (a->stuffToSend()) + iow.watch(0, 100000); + else + iow.watch(100000, 0); + if (a->hasFailed()) { + cout << "ncp: restarting\n"; + resetSocketConnections(numScp, scp, a); + delete a; + a = NULL; + } + } + delete a; + } + skt.closeSocket(); +} diff --git a/ncpd/mp_serial.c b/ncpd/mp_serial.c new file mode 100644 index 0000000..0b452f6 --- /dev/null +++ b/ncpd/mp_serial.c @@ -0,0 +1,191 @@ +/* + // PLP - An implementation of the PSION link protocol + // + // + // The code in this file was written by Rudolf Koenig + // (rfkoenig@immd4.informatik.uni-erlangen.de). (from his p3nfs code) + // The Copyright remains his + // + // + // This program is free software; you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation; either version 2 of the License, or + // (at your option) any later version. + // + // This program is distributed in the hope that it will be useful, + // but WITHOUT ANY WARRANTY; without even the implied warranty of + // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + // GNU General Public License for more details. + // + // You should have received a copy of the GNU General Public License + // along with this program; if not, write to the Free Software + // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + // + // e-mail philip.proudman@btinternet.com + */ + + +#include +#include +#include /* for usleep() */ +#include /* for bzero() */ +#include +#if defined(linux) || defined(_IBMR2) || defined(__NetBSD__) +#include /* for ioctl() */ +#endif +#include +#ifdef sun +#include /* sun has TIOCEXCL there */ +#endif +#if defined (__SVR4) +#include +#endif + +#ifndef hpux +#define mflag int +#else /* hpux */ +#include +#include +#endif + + +/* + #if !defined(CRTSCTS) && defined(_IBMR2) + #define CRTSCTS 0x80000000 + #endif + */ + +#ifdef __sgi +#define CRTSCTS CNEW_RTSCTS +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +int +init_serial(const char *dev, int speed, int debug) +{ + int fd, baud, clocal; + int uid, euid; + struct termios ti; +#ifdef hpux + struct termiox tx; +#endif + static struct baud { + int speed, baud; + } btable[] = { + { 9600, B9600 }, +#ifdef B19200 + { 19200, B19200 }, +#else +#ifdef EXTA + { 19200, EXTA }, +#endif +#endif +#ifdef B38400 + { 38400, B38400 }, +#else +#ifdef EXTB + { 38400, EXTB }, +#endif +#endif +#ifdef B57600 + { 57600, B57600 }, +#endif +#ifdef B115200 + { 115200, B115200 }, +#endif + { 4800, B4800 }, + { 2400, B2400 }, + { 1200, B1200 }, + { 300, B300 }, + { 75, B75 }, + { 50, B50 }, + { 0, 0 } + }, *bptr; + + if (speed) { + for (bptr = btable; bptr->speed; bptr++) + if (bptr->speed == speed) + break; + if (!bptr->baud) { + fprintf(stderr, "Cannot match selected speed %d\n", speed); + exit(1); + } + baud = bptr->baud; + } else + baud = 0; + + if (debug) + printf("using %s...\n", dev); + euid = geteuid(); + uid = getuid(); + +#ifdef hpux +#define seteuid(a) setresuid(-1, a, -1) +#endif + + clocal = CLOCAL; + if (seteuid(uid)) { + perror("seteuid"); + exit(1); + } + if ((fd = open(dev, O_RDWR | O_NDELAY | O_NOCTTY, 0)) < 0) { + perror(dev); + exit(1); + } + if (seteuid(euid)) { + perror("seteuid back"); + exit(1); + } + if (debug) + printf("open done\n"); +#ifdef TIOCEXCL + ioctl(fd, TIOCEXCL, (char *) 0); /* additional open() calls shall fail */ +#else + fprintf(stderr, "WARNING: opened %s non-exclusive!\n", dev); +#endif + + memset(&ti, 0, sizeof(struct termios)); +#if defined(hpux) || defined(_IBMR2) + ti.c_cflag = CS8 | HUPCL | clocal | CREAD; +#endif +#if defined(sun) || defined(linux) || defined(__sgi) || defined(__NetBSD__) + ti.c_cflag = CS8 | HUPCL | clocal | CRTSCTS | CREAD; + ti.c_iflag = IGNBRK | IGNPAR; + ti.c_cc[VMIN] = 1; + ti.c_cc[VTIME] = 0; +#endif + cfsetispeed(&ti, baud); + cfsetospeed(&ti, baud); + + if (tcsetattr(fd, TCSADRAIN, &ti) < 0) + perror("tcsetattr TCSADRAIN"); + +#ifdef hpux + bzero(&tx, sizeof(struct termiox)); + tx.x_hflag = RTSXOFF | CTSXON; + if (ioctl(fd, TCSETXW, &tx) < 0) + perror("TCSETXW"); +#endif + +#if defined(_IBMR2) + ioctl(fd, TXDELCD, "dtr"); + ioctl(fd, TXDELCD, "xon"); + ioctl(fd, TXADDCD, "rts"); /* That's how AIX does CRTSCTS */ +#endif + return fd; +} + +void +ser_exit(int fd) +{ + struct termios ti; + if (ioctl(fd, TCGETS, (caddr_t) & ti) < 0) + perror("TCGETSW"); + ti.c_cflag &= ~CRTSCTS; + if (tcsetattr(fd, TCSANOW, &ti) < 0) + perror("TCSETSW"); + (void) close(fd); +} diff --git a/ncpd/mp_serial.h b/ncpd/mp_serial.h new file mode 100644 index 0000000..4f7835a --- /dev/null +++ b/ncpd/mp_serial.h @@ -0,0 +1,7 @@ +#ifndef _mp_serial_h +#define _mp_serial_h + +int init_serial(const char *dev, int speed, int debug); +void ser_exit(int fd); + +#endif diff --git a/ncpd/ncp.cc b/ncpd/ncp.cc new file mode 100644 index 0000000..d859ea9 --- /dev/null +++ b/ncpd/ncp.cc @@ -0,0 +1,292 @@ +// +// PLP - An implementation of the PSION link protocol +// +// Copyright (C) 1999 Philip Proudman +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// e-mail philip.proudman@btinternet.com + +#include +#include +#include + +#include "bool.h" +#include "defs.h" +#include "ncp.h" +#include "linkchan.h" +#include "bufferstore.h" +#include "link.h" +#include "bufferarray.h" + +#define NCP_SENDLEN 250 + +ncp::ncp(const char *fname, int baud, IOWatch & iow) +{ + l = new link(fname, baud, iow, LINK_LAYER_DIAGNOSTICS); + gotLinkChan = false; + failed = false; + + // init channels + for (int i = 0; i < 8; i++) + channelPtr[i] = NULL; +} + +ncp::~ncp() +{ + delete l; +} + +void ncp:: +poll() +{ + bufferArray res(l->poll()); + if (!res.empty()) { + do { + bufferStore s = res.popBuffer(); + if (s.getLen() > 1) { + int channel = s.getByte(0); + s.discardFirstBytes(1); + if (channel == 0) { + decodeControlMessage(s); + } else { + /* int remChan = */ s.getByte(0); + int allData = s.getByte(1); + s.discardFirstBytes(2); + if (channelPtr[channel] == NULL) { + cerr << "Got message for unknown channel\n"; + } else { + messageList[channel].addBuff(s); + if (allData == LAST_MESS) { + channelPtr[channel]->ncpDataCallback(messageList[channel]); + messageList[channel].init(); + } else if (allData != NOT_LAST_MESS) { + cerr << "ncp: bizarre third byte!\n"; + } + } + } + } else { + cerr << "Got null message\n"; + } + } while (!res.empty()); + } +} + +void ncp:: +controlChannel(int chan, enum interControllerMessageType t, bufferStore & command) +{ + bufferStore open; + open.addByte(0); // control + + open.addByte(chan); + open.addByte(t); + open.addBuff(command); + cout << "put " << ctrlMsgName(t) << endl; + l->send(open); +} + +void ncp:: +decodeControlMessage(bufferStore & buff) +{ + int remoteChan = buff.getByte(0); + interControllerMessageType imt = (interControllerMessageType) buff.getByte(1); + buff.discardFirstBytes(2); + cout << "got " << ctrlMsgName(imt) << " " << remoteChan << " "; + switch (imt) { + case NCON_MSG_DATA_XOFF: + cout << remoteChan << " " << buff << endl; + break; + case NCON_MSG_DATA_XON: + cout << buff << endl; + break; + case NCON_MSG_CONNECT_TO_SERVER:{ + cout << buff << endl; + int localChan; + bufferStore b; + + // Ack with connect response + localChan = getFirstUnusedChan(); + b.addByte(remoteChan); + b.addByte(0x0); + controlChannel(localChan, NCON_MSG_CONNECT_RESPONSE, b); + + if (!strcmp(buff.getString(0), "LINK.*")) { + if (gotLinkChan) + failed = true; + cout << "Accepted link channel" << endl; + channelPtr[localChan] = new linkChan(this); + channelPtr[localChan]->setNcpChannel(localChan); + channelPtr[localChan]->ncpConnectAck(); + gotLinkChan = true; + } else { + cout << "Disconnecting channel" << endl; + bufferStore b; + b.addByte(remoteChan); + controlChannel(localChan, NCON_MSG_CHANNEL_DISCONNECT, b); + } + } + break; + case NCON_MSG_CONNECT_RESPONSE:{ + int forChan = buff.getByte(0); + cout << "for channel " << forChan << " status "; + if (buff.getByte(1) == 0) { + cout << "OK" << endl; + if (channelPtr[forChan]) { + remoteChanList[forChan] = remoteChan; + channelPtr[forChan]->ncpConnectAck(); + } else { + cerr << "Got message for unknown channel\n"; + } + } else { + cout << "Unknown status " << (int) buff.getByte(1) << endl; + channelPtr[forChan]->ncpConnectTerminate(); + } + } + break; + case NCON_MSG_CHANNEL_CLOSED: + cout << buff << endl; + break; + case NCON_MSG_NCP_INFO: + if (buff.getByte(0) == 6) { + cout << buff << endl; + { + // Send time info + bufferStore b; + b.addByte(6); + b.addDWord(0); + controlChannel(0, NCON_MSG_NCP_INFO, b); + } + } else + cout << "ALERT!!!! Protocol-Version is NOT 6!! (No Series 5?)!" << endl; + break; + case NCON_MSG_CHANNEL_DISCONNECT: + cout << "channel " << (int) buff.getByte(0) << endl; + disconnect(buff.getByte(0)); + break; + case NCON_MSG_NCP_END: + cout << buff << endl; + break; + default: + cout << endl; + } +} + +int ncp:: +getFirstUnusedChan() +{ + for (int cNum = 1; cNum < 8; cNum++) { + if (channelPtr[cNum] == NULL) { + return cNum; + } + } + return 0; +} + +int ncp:: +connect(channel * ch) +{ + // look for first unused chan + int cNum = getFirstUnusedChan(); + if (cNum > 0) { + channelPtr[cNum] = ch; + ch->setNcpChannel(cNum); + bufferStore b; + b.addString(ch->getNcpConnectName()); + b.addByte(0); + controlChannel(cNum, NCON_MSG_CONNECT_TO_SERVER, b); + return cNum; + } + return -1; +} + +void ncp:: +send(int channel, bufferStore & a) +{ + bool last; + do { + last = true; + + if (a.getLen() > NCP_SENDLEN) + last = false; + + bufferStore out; + out.addByte(remoteChanList[channel]); + out.addByte(channel); + + if (last) { + out.addByte(LAST_MESS); + } else { + out.addByte(NOT_LAST_MESS); + } + + out.addBuff(a, NCP_SENDLEN); + a.discardFirstBytes(NCP_SENDLEN); + l->send(out); + } while (!last); +} + +void ncp:: +disconnect(int channel) +{ + channelPtr[channel]->terminateWhenAsked(); + channelPtr[channel] = NULL; + bufferStore b; + b.addByte(remoteChanList[channel]); + controlChannel(channel, NCON_MSG_CHANNEL_DISCONNECT, b); +} + +bool ncp:: +stuffToSend() +{ + return l->stuffToSend(); +} + +bool ncp:: +hasFailed() +{ + if (failed) + return true; + return l->hasFailed(); +} + +bool ncp:: +gotLinkChannel() +{ + return gotLinkChan; +} + +char *ncp:: +ctrlMsgName(unsigned char msgType) +{ + switch (msgType) { + case NCON_MSG_DATA_XOFF: + return "NCON_MSG_DATA_XOFF"; + case NCON_MSG_DATA_XON: + return "NCON_MSG_DATA_XON"; + case NCON_MSG_CONNECT_TO_SERVER: + return "NCON_MSG_CONNECT_TO_SERVER"; + case NCON_MSG_CONNECT_RESPONSE: + return "NCON_MSG_CONNECT_RESPONSE"; + case NCON_MSG_CHANNEL_CLOSED: + return "NCON_MSG_CHANNEL_CLOSED"; + case NCON_MSG_NCP_INFO: + return "NCON_MSG_NCP_INFO"; + case NCON_MSG_CHANNEL_DISCONNECT: + return "NCON_MSG_CHANNEL_DISCONNECT"; + case NCON_MSG_NCP_END: + return "NCON_MSG_NCP_END"; + } + return "NCON_MSG_UNKNOWN"; +} diff --git a/ncpd/ncp.h b/ncpd/ncp.h new file mode 100644 index 0000000..9e8444c --- /dev/null +++ b/ncpd/ncp.h @@ -0,0 +1,49 @@ +#ifndef _ncp_h_ +#define _ncp_h_ + +#include "bool.h" +#include "bufferstore.h" +class link; +class channel; +class IOWatch; + +class ncp { + public: + ncp(const char *fname, int baud, IOWatch &iow); + ~ncp(); + + int connect(channel *c); // returns channel, or -1 if failure + void disconnect(int channel); + void send(int channel, bufferStore &a); + void poll(); + bool stuffToSend(); + bool hasFailed(); + bool gotLinkChannel(); + + private: + enum c { MAX_LEN = 200, LAST_MESS = 1, NOT_LAST_MESS = 2 }; + enum interControllerMessageType { + // Inter controller message types + NCON_MSG_DATA_XOFF=1, + NCON_MSG_DATA_XON=2, + NCON_MSG_CONNECT_TO_SERVER=3, + NCON_MSG_CONNECT_RESPONSE=4, + NCON_MSG_CHANNEL_CLOSED=5, + NCON_MSG_NCP_INFO=6, + NCON_MSG_CHANNEL_DISCONNECT=7, + NCON_MSG_NCP_END=8 + }; + int getFirstUnusedChan(); + void decodeControlMessage(bufferStore &buff); + void controlChannel(int chan, enum interControllerMessageType t, bufferStore &command); + char * ctrlMsgName(unsigned char); + + link *l; + channel *channelPtr[8]; + bufferStore messageList[8]; + int remoteChanList[8]; + bool gotLinkChan; + bool failed; +}; + +#endif diff --git a/ncpd/packet.cc b/ncpd/packet.cc new file mode 100644 index 0000000..62f6b09 --- /dev/null +++ b/ncpd/packet.cc @@ -0,0 +1,226 @@ +// +// PLP - An implementation of the PSION link protocol +// +// Copyright (C) 1999 Philip Proudman +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// e-mail philip.proudman@btinternet.com + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include "mp_serial.h" +} +#include "bool.h" +#include "bufferstore.h" +#include "packet.h" +#include "iowatch.h" + +#define BUFFERLEN 2000 + +packet::packet(const char *fname, int _baud, IOWatch & _iow, bool _verbose): +iow(_iow) +{ + verbose = _verbose; + devname = strdup(fname); + baud = _baud; + inPtr = inBuffer = new unsigned char[BUFFERLEN + 1]; + outPtr = outBuffer = new unsigned char[BUFFERLEN + 1]; + inLen = outLen = termLen = 0; + esc = false; + crcIn = crcOut = 0; + + fd = init_serial(devname, baud, 0); + iow.addIO(fd); +} + +packet::~packet() +{ + iow.remIO(fd); + ser_exit(fd); + usleep(100000); + + delete[]inBuffer; + delete[]outBuffer; + free(devname); +} + +void packet:: +send(unsigned char type, const bufferStore & b) +{ + if (verbose) + cout << "packet: send "; + opByte(0x16); + opByte(0x10); + opByte(0x02); + + crcOut = 0; + opByte(type); + addToCrc(type, &crcOut); + + long len = b.getLen(); + for (int i = 0; i < len; i++) { + unsigned char c = b.getByte(i); + if (c == 0x10) + opByte(c); + opByte(c); + addToCrc(c, &crcOut); + } + + opByte(0x10); + opByte(0x03); + + opByte(crcOut >> 8); + opByte(crcOut & 0xff); + if (verbose) + cout << endl; + realWrite(); +} + +void packet:: +addToCrc(unsigned short c, unsigned short *crc) +{ + c <<= 8; + for (int i = 0; i < 8; i++) { + if ((*crc ^ c) & 0x8000) + *crc = (*crc << 1) ^ 0x1021; + else + *crc <<= 1; + c <<= 1; + } +} + +void packet:: +opByte(unsigned char a) +{ + *outPtr++ = a; + outLen++; + if (verbose) + cout << hex << setw(2) << setfill('0') << (int) a << " "; + if (outLen >= BUFFERLEN) + realWrite(); +} + +void packet:: +realWrite() +{ + outPtr = outBuffer; + while (outLen > 0) { + int r = write(fd, outPtr, outLen); + if (verbose) + cout << "realW:" << dec << r << endl; + if (r > 0) { + outLen -= r; + outPtr += r; + } + } + outPtr = outBuffer; +} + +bool packet:: +get(unsigned char &type, bufferStore & ret) +{ + while (!terminated()) { + int res = read(fd, inPtr, BUFFERLEN - inLen); + if (res > 0) { + if (verbose) + cout << "packet: rcv " << dec << res << endl; + inPtr += res; + inLen += res; + } + if (res < 0) + return false; + if (inLen >= BUFFERLEN) { + cerr << "input Overflow!!!!" << endl; + inLen = 0; + inPtr = inBuffer; + return false; + } + } + if (verbose) { + cout << "packet: get "; + for (int i = 0; i < termLen; i++) + cout << hex << setw(2) << setfill('0') << (int) inBuffer[i] << " "; + cout << endl; + } + inLen -= termLen; + termLen = 0; + bool crcOk = (endPtr[0] == ((crcIn >> 8) & 0xff) && endPtr[1] == (crcIn & 0xff)); + if (inLen > 0) + memmove(inBuffer, &endPtr[2], inLen); + inPtr = inBuffer + inLen; + if (crcOk) { + type = rcv.getByte(0); + ret = rcv; + ret.discardFirstBytes(1); + return true; + } else + cout << "packet::Warning - bad crc packet " << endl; + return false; +} + +bool packet:: +terminated() +{ + unsigned char *p; + int l; + + if (inLen < 6) + return false; + p = inBuffer + termLen; + if (termLen == 0) { + if (*p++ != 0x16) + return false; + if (*p++ != 0x10) + return false; + if (*p++ != 0x02) + return false; + esc = false; + termLen = 3; + crcIn = 0; + rcv.init(); + } + for (l = termLen; l < inLen - 2; p++, l++) { + if (esc) { + esc = false; + if (*p == 0x03) { + endPtr = p + 1; + termLen = l + 3; + return true; + } + addToCrc(*p, &crcIn); + rcv.addByte(*p); + } else { + if (*p == 0x10) + esc = true; + else { + addToCrc(*p, &crcIn); + rcv.addByte(*p); + } + } + } + termLen = l; + return false; +} diff --git a/ncpd/packet.h b/ncpd/packet.h new file mode 100644 index 0000000..cd02513 --- /dev/null +++ b/ncpd/packet.h @@ -0,0 +1,43 @@ +#ifndef _packet_h +#define _packet_h + +#include + +#include "bool.h" +class psiEmul; +class bufferStore; +class IOWatch; + +class packet { + public: + packet(const char *fname, int baud, IOWatch &iow, bool verbose = false); + ~packet(); + void send(unsigned char type, const bufferStore &b); + bool get(unsigned char &type, bufferStore &b); + + private: + bool terminated(); + void addToCrc(unsigned short a, unsigned short *crc); + void opByte(unsigned char a); + void realWrite(); + + unsigned short crcOut; + unsigned short crcIn; + unsigned char *inPtr; + unsigned char *outPtr; + unsigned char *endPtr; + unsigned char *inBuffer; + unsigned char *outBuffer; + bufferStore rcv; + int inLen; + int outLen; + int termLen; + int fd; + bool verbose; + bool esc; + char *devname; + int baud; + IOWatch &iow; +}; + +#endif diff --git a/ncpd/socketchan.cc b/ncpd/socketchan.cc new file mode 100644 index 0000000..0afabf2 --- /dev/null +++ b/ncpd/socketchan.cc @@ -0,0 +1,105 @@ +// +// PLP - An implementation of the PSION link protocol +// +// Copyright (C) 1999 Philip Proudman +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// e-mail philip.proudman@btinternet.com + +#include +#include "stdio.h" +#include "string.h" +#include "malloc.h" + +#include "bool.h" +#include "socketchan.h" +#include "ncp.h" +#include "ppsocket.h" +#include "iowatch.h" + +socketChan::socketChan(ppsocket *_skt, ncp *_ncpController, IOWatch &_iow) : + channel(_ncpController), + iow(_iow) +{ + skt = _skt; + connectName = 0; + iow.addIO(skt->socket()); + connected = false; +} + +socketChan::~socketChan() { + iow.remIO(skt->socket()); + skt->closeSocket(); + delete skt; + if (connectName) free(connectName); +} + +void socketChan::ncpDataCallback(bufferStore &a) { + if (connectName != 0) { + skt->sendBufferStore(a); + } + else { + cerr << "This should not happen\n"; + } +} + +const char *socketChan::getNcpConnectName() { + return connectName; +} + +void socketChan::ncpConnectAck() { + bufferStore a; + a.addStringT("Ok"); + skt->sendBufferStore(a); + connected = true; +} + +void socketChan::ncpConnectTerminate() { + bufferStore a; + a.addStringT("Close"); + skt->sendBufferStore(a); + terminateWhenAsked(); +} + +void socketChan::socketPoll() { + if (connectName == 0) { + bufferStore a; + if (skt->getBufferStore(a, false) == 1) { + connectName = strdup(a.getString()); + ncpConnect(); + } + } + else if (connected) { + bufferStore a; + int res = skt->getBufferStore(a, false); + if ( res == -1 ) { + ncpDisconnect(); + } + else if (res == 1) { + if (a.getLen() > 5 && + !strncmp(a.getString(), "Close", 5)) { + ncpDisconnect(); + } + else { + ncpSend(a); + } + } + } +} + +bool socketChan::isConnected() const { + return connected; +} diff --git a/ncpd/socketchan.h b/ncpd/socketchan.h new file mode 100644 index 0000000..0911c0c --- /dev/null +++ b/ncpd/socketchan.h @@ -0,0 +1,28 @@ +#ifndef _socketchan_h_ +#define _socketchan_h_ + +#include "bool.h" +#include "channel.h" +class ppsocket; +class IOWatch; + +class socketChan : public channel { +public: + socketChan(ppsocket* comms, ncp* ncpController, IOWatch &iow); + virtual ~socketChan(); + + void ncpDataCallback(bufferStore& a); + const char* getNcpConnectName(); + void ncpConnectAck(); + void ncpConnectTerminate(); + + bool isConnected() const; + void socketPoll(); +private: + ppsocket* skt; + IOWatch &iow; + char* connectName; + bool connected; +}; + +#endif -- cgit v1.2.3