From bf203bc761972ff5dd3fc992ed9851a6f7f5148a Mon Sep 17 00:00:00 2001 From: Konrad Rosenbaum Date: Mon, 26 May 2014 21:55:54 +0200 Subject: [PATCH] implement SIT and document it --- doc/index.html | 1 + doc/sitex-protocol.html | 76 ++++++++++++++++ examples/system-in-test/sit.pro | 2 + examples/system-in-test/sitmain.cpp | 169 +++++++++++++++++++++++++++++++++++ examples/system-in-test/sitmain.h | 61 +++++++++++++ 5 files changed, 309 insertions(+), 0 deletions(-) create mode 100644 doc/sitex-protocol.html create mode 100644 examples/system-in-test/sitmain.h diff --git a/doc/index.html b/doc/index.html index e770369..acfc8ae 100644 --- a/doc/index.html +++ b/doc/index.html @@ -31,6 +31,7 @@ development.

  • SKID Internals:
    1. The Runner-Controller-Protocol
    2. TODO: C++ signalling mechanism
    3. +
    4. The protocol of the System-In-Test example
  • diff --git a/doc/sitex-protocol.html b/doc/sitex-protocol.html new file mode 100644 index 0000000..42ec08e --- /dev/null +++ b/doc/sitex-protocol.html @@ -0,0 +1,76 @@ + +Protocol of the System-In-Test Example + +

    Protocol of the System-In-Test Example

    + +

    The protocol of the System-In-Test example is a simple line-by-line ASCII protocol. The client (runner) sends a request line and the server (System-In-Test) responds with an ASCII line. Then the protocol repeats.

    + +

    Each line is terminated with a simple newline (carriage-return plus newline will be tolerated from the client, but will never be sent). Command and parameter are separated by a single space (tab will not work).

    + +

    Each connection keeps an integer state that is initialized at zero.

    + +

    Requests

    + +

    Requests are formatted as command without parameters or as command parameter.

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CommandDescription
    add numberAdds the number to the internal state. The number must be a decimal integer. The successful response will contain the new state.
    resetResets the connection state to zero.
    countThe successful response returns the number of open connections instead of the state.
    closeCloses the connection. There is no response on success.
    quitExits the entire system. There is no response on success.
    + +

    Responses

    + +

    Responses always start with ok for successful commands or error for indicating problems.

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ResponseDescription
    ok numberThe command was successful. The number contains the current state or (after count) the number of connections.
    error nanThe parameter was not a number.
    error paramThe number of parameter was not correct.
    error commandThe command was not understood.
    error nocommandThere was no command.
    + + + + \ No newline at end of file diff --git a/examples/system-in-test/sit.pro b/examples/system-in-test/sit.pro index a2a75c7..cbab16f 100644 --- a/examples/system-in-test/sit.pro +++ b/examples/system-in-test/sit.pro @@ -2,9 +2,11 @@ TEMPLATE = app TARGET = sit QT -= gui +QT += network include(../../common.pri) DESTDIR = $$BINDIR #our actual sources: SOURCES += sitmain.cpp +HEADERS += sitmain.h \ No newline at end of file diff --git a/examples/system-in-test/sitmain.cpp b/examples/system-in-test/sitmain.cpp index 2717afb..f4dbd9d 100644 --- a/examples/system-in-test/sitmain.cpp +++ b/examples/system-in-test/sitmain.cpp @@ -1,8 +1,177 @@ +// +// SKID Examples: System In Test +// +// +// Author: Konrad Rosenbaum , (C) 2014 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + #include +#include +#include +#include +#include +#include + +#include "sitmain.h" + +void ServerBase::newConnection() +{ + qDebug()<<"Ooops. This should not have happened."; +} + +int Connection::cctr=0; + +Connection::Connection ( QIODevice *s ) : sock(s) +{ + s->setParent(this); + connect(s,SIGNAL(readyRead()),this,SLOT(read())); + connect(s,SIGNAL(disconnected()),this,SLOT(close())); + cctr++; +} + +Connection::~Connection() +{ + if(sock)sock->close(); + sock=nullptr; + cctr--; +} +void Connection::read() +{ + if(sock==nullptr)return; + const QStringList line=QString::fromLatin1(sock->readLine()).trimmed().split(' '); + if(line.size()<1){ + sock->write("error nocommand\n"); + return; + } + if(line[0].isEmpty()){ + sock->write("error nocommand\n"); + return; + } + if(line[0]=="quit"){ + if(line.size()!=1){ + sock->write("error param\n"); + return; + } + qApp->quit(); + return; + } + if(line[0]=="close"){ + if(line.size()!=1){ + sock->write("error param\n"); + return; + } + close(); + return; + } + if(line[0]=="count"){ + if(line.size()!=1){ + sock->write("error param\n"); + return; + } + sock->write(QString("ok %1\n").arg(cctr).toLatin1()); + return; + } + if(line[0]=="add"){ + if(line.size()!=2){ + sock->write("error param\n"); + return; + } + bool ok; + int add=line[1].toInt(&ok); + if(!ok){ + sock->write("error nan\n"); + return; + } + state+=add; + sock->write(QString("ok %1\n").arg(state).toLatin1()); + return; + } + if(line[0]=="reset"){ + if(line.size()!=1){ + sock->write("error param\n"); + return; + } + state=0; + sock->write(QString("ok 0\n").toLatin1()); + return; + } + //no match + sock->write("error command\n"); +} + +void Connection::close() +{ + deleteLater(); +} + +Server* tcpServer(quint16 port) +{ + QTcpServer*sock=new QTcpServer; + if(sock->listen(QHostAddress::Any,port)){ + return new Server(sock); + }else{ + sock->deleteLater(); + return nullptr; + } +} + +Server* localServer(const QString&path) +{ + QLocalServer*sock=new QLocalServer; + if(sock->listen(path)){ + return new Server(sock); + }else{ + sock->deleteLater(); + return nullptr; + } +} + +void usage() +{ + qDebug()<<"Usage: sit [options...]"; + qDebug()<<"\t-port=## -- create a TCP server, ## must be an integer between 1 and 65535"; + qDebug()<<"\t-sock=path -- create a local server, path must be a valid path name for it"; +} int main(int ac,char**av) { QCoreApplication app(ac,av); + + bool havesock=false; + for(const QString&arg:app.arguments().mid(1)){ + if(arg.startsWith("-port=")){ + bool ok; + const int port=arg.mid(6).toInt(&ok); + if(!ok || port<1 || port>65535){ + qDebug()<<"Not a valid port number:"<, (C) 2014 +// +// Copyright: See README/COPYING files that come with this distribution +// +// + +#ifndef SKID_EXAMPLE_SITMAIN_H +#define SKID_EXAMPLE_SITMAIN_H + +#include + +class Connection:public QObject +{ + Q_OBJECT + private: + QIODevice*sock; + int state=0; + static int cctr; + public: + explicit Connection (QIODevice*s); + virtual ~Connection(); + private slots: + void read(); + void close(); +}; + +class ServerBase:public QObject +{ + Q_OBJECT + public: + ServerBase(){} + protected slots: + virtual void newConnection(); +}; + +template +class Server:public ServerBase +{ + private: + ServerSocket*server; + public: + Server(ServerSocket*s) + { + server=s; + s->setParent(this); + connect(s,SIGNAL(newConnection()),this,SLOT(newConnection())); + } + + protected: + virtual void newConnection()override + { + while(server->hasPendingConnections()) + new Connection(server->nextPendingConnection()); + } +}; + +#endif -- 1.7.2.5