From ec3b548646d8739c35e2a66379e921b3438fe367 Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Tue, 22 May 2001 21:56:49 +0000 Subject: - Added support for extended sequence numbers (incoming only) - Changed the behavior on initial connect to support the Clipboard-Server and to meet the doc in http://www.thouky.co.uk/software/psifs/plp.html: All services except SYS$RFSV now perform registration and connect is done when the Psion returned RegisterAck. Then the connect can use the service name as presented by the Psion's RegisterAck. --- ncpd/ncp.cc | 613 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 316 insertions(+), 297 deletions(-) (limited to 'ncpd/ncp.cc') diff --git a/ncpd/ncp.cc b/ncpd/ncp.cc index bf99cac..31ce2c3 100644 --- a/ncpd/ncp.cc +++ b/ncpd/ncp.cc @@ -1,27 +1,26 @@ -// $Id$ -// -// PLP - An implementation of the PSION link protocol -// -// Copyright (C) 1999 Philip Proudman -// Modifications for plptools: -// Copyright (C) 1999 Fritz Elfert -// -// 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 - +/*-*-c++-*- + * $Id$ + * + * This file is part of plptools. + * + * Copyright (C) 1999 Philip Proudman + * Copyright (C) 1999-2001 Fritz Elfert + * + * 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 + * + */ #ifdef HAVE_CONFIG_H #include #endif @@ -32,400 +31,420 @@ #include "ncp.h" #include "linkchan.h" -#include "bufferstore.h" +#include #include "link.h" -#include "bufferarray.h" +#include #define NCP_SENDLEN 250 ncp::ncp(const char *fname, int baud, IOWatch & iow) { - l = new link(fname, baud, iow); - failed = false; - verbose = 0; - protocolVersion = PV_SERIES_5; // until detected on receipt of INFO - - // init channels - for (int i = 0; i < MAX_CHANNEL; i++) - channelPtr[i] = NULL; + l = new link(fname, baud, iow); + failed = false; + verbose = 0; + protocolVersion = PV_SERIES_5; // until detected on receipt of INFO + + // init channels + for (int i = 0; i < MAX_CHANNEL; i++) + channelPtr[i] = NULL; } ncp::~ncp() { - bufferStore b; - for (int i = 0; i < MAX_CHANNEL; i++) { - if (channelPtr[i]) { - bufferStore b2; - b2.addByte(remoteChanList[i]); - controlChannel(i, NCON_MSG_CHANNEL_DISCONNECT, b2); - } - channelPtr[i] = NULL; + bufferStore b; + for (int i = 0; i < MAX_CHANNEL; i++) { + if (channelPtr[i]) { + bufferStore b2; + b2.addByte(remoteChanList[i]); + controlChannel(i, NCON_MSG_CHANNEL_DISCONNECT, b2); } - controlChannel(0, NCON_MSG_NCP_END, b); - delete l; + channelPtr[i] = NULL; + } + controlChannel(0, NCON_MSG_NCP_END, b); + delete l; } void ncp:: reset() { - for (int i = 0; i < MAX_CHANNEL; i++) { - if (channelPtr[i]) - channelPtr[i]->terminateWhenAsked(); - channelPtr[i] = NULL; - } - failed = false; - lChan = NULL; - protocolVersion = PV_SERIES_5; // until detected on receipt of INFO - l->reset(); + for (int i = 0; i < MAX_CHANNEL; i++) { + if (channelPtr[i]) + channelPtr[i]->terminateWhenAsked(); + channelPtr[i] = NULL; + } + failed = false; + lChan = NULL; + protocolVersion = PV_SERIES_5; // until detected on receipt of INFO + l->reset(); } short int ncp:: getVerbose() { - return verbose; + return verbose; } void ncp:: setVerbose(short int _verbose) { - verbose = _verbose; + verbose = _verbose; } short int ncp:: getLinkVerbose() { - return l->getVerbose(); + return l->getVerbose(); } void ncp:: setLinkVerbose(short int _verbose) { - l->setVerbose(_verbose); + l->setVerbose(_verbose); } short int ncp:: getPktVerbose() { - return l->getPktVerbose(); + return l->getPktVerbose(); } void ncp:: setPktVerbose(short int _verbose) { - l->setPktVerbose(_verbose); + l->setPktVerbose(_verbose); } short int ncp:: getProtocolVersion() { - return protocolVersion; + return protocolVersion; } void ncp:: poll() { - bufferArray res(l->poll()); - if (!res.empty()) { - do { - bufferStore s = res.pop(); - 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 << "ncp: 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"; + bufferArray res(l->poll()); + if (!res.empty()) { + do { + bufferStore s = res.pop(); + 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 << "ncp: 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"; } - } while (!res.empty()); - } + } + } + } 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); - if (verbose & NCP_DEBUG_LOG) - cout << "ncp: >> " << ctrlMsgName(t) << " " << chan << endl; - l->send(open); + bufferStore open; + open.addByte(0); // control + + open.addByte(chan); + open.addByte(t); + open.addBuff(command); + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: >> " << ctrlMsgName(t) << " " << chan << endl; + l->send(open); } void ncp:: decodeControlMessage(bufferStore & buff) { - int remoteChan = buff.getByte(0); - short int ver; - interControllerMessageType imt = (interControllerMessageType) buff.getByte(1); - buff.discardFirstBytes(2); - if (verbose & NCP_DEBUG_LOG) - cout << "ncp: << " << ctrlMsgName(imt) << " " << remoteChan; - switch (imt) { - case NCON_MSG_CONNECT_TO_SERVER: - { - if (verbose & NCP_DEBUG_LOG) { - if (verbose & NCP_DEBUG_DUMP) - cout << " [" << buff << "]"; - cout << endl; - } - int localChan; - bufferStore b; - - // Ack with connect response - localChan = getFirstUnusedChan(); - b.addByte(remoteChan); - b.addByte(0x0); - controlChannel(localChan, NCON_MSG_CONNECT_RESPONSE, b); - - // NOTE: we don't allow connections from the - // Psion to any local "processes" other than - // LINK.* - Matt might need to change this for - // his NCP<->TCP/IP bridge code... - - if (!strcmp(buff.getString(0), "LINK.*")) { - if (lChan) - failed = true; - if (verbose & NCP_DEBUG_LOG) - cout << "ncp: Link UP" << endl; - channelPtr[localChan] = lChan = new linkChan(this); - lChan->setNcpChannel(localChan); - lChan->ncpConnectAck(); - lChan->setVerbose(verbose); - } else { - if (verbose & NCP_DEBUG_LOG) - cout << "ncp: Link DOWN" << endl; - bufferStore b; - b.addByte(remoteChan); - controlChannel(localChan, NCON_MSG_CHANNEL_DISCONNECT, b); - } - } - break; - case NCON_MSG_CONNECT_RESPONSE: - { - int forChan = buff.getByte(0); - if (verbose & NCP_DEBUG_LOG) - cout << " ch=" << forChan << " stat="; - if (buff.getByte(1) == 0) { - if (verbose & NCP_DEBUG_LOG) - cout << "OK" << endl; - if (channelPtr[forChan]) { - remoteChanList[forChan] = remoteChan; - channelPtr[forChan]->ncpConnectAck(); - } else { - if (verbose & NCP_DEBUG_LOG) - cout << "ncp: message for unknown channel" << endl; - } - } else { - if (verbose & NCP_DEBUG_LOG) - cout << "Unknown " << (int) buff.getByte(1) << endl; - channelPtr[forChan]->ncpConnectNak(); - } - } - break; - case NCON_MSG_NCP_INFO: - ver = buff.getByte(0); - // Series 3c returns '3', as does mclink. PsiWin 1.1 - // returns version 2. We return whatever version we're - // sent, which is rather crude, but works for Series 3 - // and probably 5. If Symbian have changed EPOC Connect - // for the Series 5mx/7, this may need to change. - // - if (ver == PV_SERIES_5 || ver == PV_SERIES_3) { - bufferStore b; - protocolVersion = ver; - if (verbose & NCP_DEBUG_LOG) { - if (verbose & NCP_DEBUG_DUMP) - cout << " [" << buff << "]"; - cout << endl; - } - // Fake NCP version 2 for a Series 3 (behave like PsiWin 1.1) - if (ver == PV_SERIES_3) - ver = 2; - b.addByte(ver); - // Do we send a time of 0 or a real time? - // The Psion uses this to determine whether to - // restart. (See protocol docs for details) - // b.addDWord(0); - b.addDWord(time(NULL)); - controlChannel(0, NCON_MSG_NCP_INFO, b); - } else - cout << "ALERT!!!! Unexpected Protocol Version!! (No Series 5/3?)!" << endl; - break; - case NCON_MSG_CHANNEL_DISCONNECT: - if (verbose & NCP_DEBUG_LOG) - cout << " ch=" << (int) buff.getByte(0) << endl; - disconnect(buff.getByte(0)); - break; - case NCON_MSG_DATA_XOFF: - case NCON_MSG_DATA_XON: - case NCON_MSG_CHANNEL_CLOSED: - case NCON_MSG_NCP_END: - default: - if (verbose & NCP_DEBUG_LOG) { - if (verbose & NCP_DEBUG_DUMP) - cout << " [" << buff << "]"; - cout << endl; - } + int remoteChan = buff.getByte(0); + short int ver; + interControllerMessageType imt = (interControllerMessageType) buff.getByte(1); + buff.discardFirstBytes(2); + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: << " << ctrlMsgName(imt) << " " << remoteChan; + switch (imt) { + case NCON_MSG_CONNECT_TO_SERVER: + { + if (verbose & NCP_DEBUG_LOG) { + if (verbose & NCP_DEBUG_DUMP) + cout << " [" << buff << "]"; + cout << endl; + } + int localChan; + bufferStore b; + + // Ack with connect response + localChan = getFirstUnusedChan(); + b.addByte(remoteChan); + b.addByte(0x0); + controlChannel(localChan, NCON_MSG_CONNECT_RESPONSE, b); + + // NOTE: we don't allow connections from the + // Psion to any local "processes" other than + // LINK.* - Matt might need to change this for + // his NCP<->TCP/IP bridge code... + + if (!strcmp(buff.getString(0), "LINK.*")) { + if (lChan) + failed = true; + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: Link UP" << endl; + channelPtr[localChan] = lChan = new linkChan(this); + lChan->setNcpChannel(localChan); + lChan->ncpConnectAck(); + lChan->setVerbose(verbose); + } else { + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: Link DOWN" << endl; + bufferStore b; + b.addByte(remoteChan); + controlChannel(localChan, NCON_MSG_CHANNEL_DISCONNECT, b); + } } + break; + case NCON_MSG_CONNECT_RESPONSE: + { + int forChan = buff.getByte(0); + if (verbose & NCP_DEBUG_LOG) + cout << " ch=" << forChan << " stat="; + if (buff.getByte(1) == 0) { + if (verbose & NCP_DEBUG_LOG) + cout << "OK" << endl; + if (channelPtr[forChan]) { + remoteChanList[forChan] = remoteChan; + channelPtr[forChan]->ncpConnectAck(); + } else { + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: message for unknown channel" << endl; + } + } else { + if (verbose & NCP_DEBUG_LOG) + cout << "Unknown " << (int) buff.getByte(1) << endl; + channelPtr[forChan]->ncpConnectNak(); + } + } + break; + case NCON_MSG_NCP_INFO: + ver = buff.getByte(0); + // Series 3c returns '3', as does mclink. PsiWin 1.1 + // returns version 2. We return whatever version we're + // sent, which is rather crude, but works for Series 3 + // and probably 5. If Symbian have changed EPOC Connect + // for the Series 5mx/7, this may need to change. + // + if (ver == PV_SERIES_5 || ver == PV_SERIES_3) { + bufferStore b; + protocolVersion = ver; + if (verbose & NCP_DEBUG_LOG) { + if (verbose & NCP_DEBUG_DUMP) + cout << " [" << buff << "]"; + cout << endl; + } + // Fake NCP version 2 for a Series 3 (behave like PsiWin 1.1) + if (ver == PV_SERIES_3) + ver = 2; + b.addByte(ver); + // Do we send a time of 0 or a real time? + // The Psion uses this to determine whether to + // restart. (See protocol docs for details) + // b.addDWord(0); + b.addDWord(time(NULL)); + controlChannel(0, NCON_MSG_NCP_INFO, b); + } else + cout << "ALERT!!!! Unexpected Protocol Version!! (No Series 5/3?)!" << endl; + break; + case NCON_MSG_CHANNEL_DISCONNECT: + if (verbose & NCP_DEBUG_LOG) + cout << " ch=" << (int) buff.getByte(0) << endl; + disconnect(buff.getByte(0)); + break; + case NCON_MSG_DATA_XOFF: + case NCON_MSG_DATA_XON: + case NCON_MSG_CHANNEL_CLOSED: + case NCON_MSG_NCP_END: + default: + if (verbose & NCP_DEBUG_LOG) { + if (verbose & NCP_DEBUG_DUMP) + cout << " [" << buff << "]"; + cout << endl; + } + } } int ncp:: getFirstUnusedChan() { - for (int cNum = 1; cNum < MAX_CHANNEL; cNum++) { - if (channelPtr[cNum] == NULL) { - if (verbose & NCP_DEBUG_LOG) - cout << "ncp: getFirstUnusedChan=" << cNum << endl; - return cNum; - } + for (int cNum = 1; cNum < MAX_CHANNEL; cNum++) { + if (channelPtr[cNum] == NULL) { + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: getFirstUnusedChan=" << cNum << endl; + return cNum; } - return 0; + } + return 0; } void ncp:: -RegisterAck(int chan) +RegisterAck(int chan, const char *name) { - if (verbose & NCP_DEBUG_LOG) - cout << "ncp: RegisterAck: chan=" << chan << endl; - for (int cNum = 1; cNum < MAX_CHANNEL; cNum++) { - channel *ch = channelPtr[cNum]; - if (ch->getNcpChannel() == chan) { - ch->ncpRegisterAck(); - return; - } + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: RegisterAck: chan=" << chan << endl; + for (int cNum = 1; cNum < MAX_CHANNEL; cNum++) { + channel *ch = channelPtr[cNum]; + if (ch->getNcpChannel() == chan) { + ch->setNcpConnectName(name); + ch->ncpRegisterAck(); + return; } - cerr << "ncp: RegisterAck: no channel to deliver" << endl; + } + cerr << "ncp: RegisterAck: no channel to deliver" << endl; } void ncp:: Register(channel * ch) { - if (lChan) - lChan->Register(ch); - else - cerr << "ncp: Register without established lChan" << endl; + if (lChan) { + int cNum = ch->getNcpChannel(); + if (cNum == 0) + cNum = getFirstUnusedChan(); + if (cNum > 0) { + channelPtr[cNum] = ch; + ch->setNcpChannel(cNum); + lChan->Register(ch); + } else + cerr << "ncp: Out of channels in register" << endl; + } else + cerr << "ncp: Register without established lChan" << endl; } int ncp:: connect(channel * ch) { - // look for first unused chan - int cNum = ch->getNcpChannel(); - if (cNum == 0) - cNum = getFirstUnusedChan(); - if (cNum > 0) { - channelPtr[cNum] = ch; - ch->setNcpChannel(cNum); - bufferStore b; - b.addString(ch->getNcpConnectName()); - b.addString(".*"); - b.addByte(0); - controlChannel(cNum, NCON_MSG_CONNECT_TO_SERVER, b); - return cNum; + // look for first unused chan + + int cNum = ch->getNcpChannel(); + if (cNum == 0) + cNum = getFirstUnusedChan(); + if (cNum > 0) { + channelPtr[cNum] = ch; + ch->setNcpChannel(cNum); + bufferStore b; + if (ch->getNcpConnectName()) + b.addString(ch->getNcpConnectName()); + else { + b.addString(ch->getNcpRegisterName()); + b.addString(".*"); } - return -1; + 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; + bool last; + do { + last = true; - if (a.getLen() > NCP_SENDLEN) - last = false; + if (a.getLen() > NCP_SENDLEN) + last = false; - bufferStore out; - out.addByte(remoteChanList[channel]); - out.addByte(channel); + bufferStore out; + out.addByte(remoteChanList[channel]); + out.addByte(channel); - if (last) { - out.addByte(LAST_MESS); - } else { - out.addByte(NOT_LAST_MESS); - } + 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); + out.addBuff(a, NCP_SENDLEN); + a.discardFirstBytes(NCP_SENDLEN); + l->send(out); + } while (!last); } void ncp:: disconnect(int channel) { - if (channelPtr[channel] == NULL) { - cerr << "ncp: Ignored disconnect for unknown channel #" << channel << endl; - return; - } - channelPtr[channel]->terminateWhenAsked(); - if (verbose & NCP_DEBUG_LOG) - cout << "ncp: disconnect: channel=" << channel << endl; - channelPtr[channel] = NULL; - bufferStore b; - b.addByte(remoteChanList[channel]); - controlChannel(channel, NCON_MSG_CHANNEL_DISCONNECT, b); + if (channelPtr[channel] == NULL) { + cerr << "ncp: Ignored disconnect for unknown channel #" << channel << endl; + return; + } + channelPtr[channel]->terminateWhenAsked(); + if (verbose & NCP_DEBUG_LOG) + cout << "ncp: disconnect: channel=" << channel << endl; + channelPtr[channel] = NULL; + bufferStore b; + b.addByte(remoteChanList[channel]); + controlChannel(channel, NCON_MSG_CHANNEL_DISCONNECT, b); } bool ncp:: stuffToSend() { - return l->stuffToSend(); + return l->stuffToSend(); } bool ncp:: hasFailed() { - if (failed) - return true; - return l->hasFailed(); + if (failed) + return true; + return l->hasFailed(); } bool ncp:: gotLinkChannel() { - return (lChan != NULL); + return (lChan != NULL); } 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"; + 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"; } + +/* + * Local variables: + * c-basic-offset: 4 + * End: + */ -- cgit v1.2.3