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:
- The Runner-Controller-Protocol
- TODO: C++ signalling mechanism
+ - 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.
+
+
+
+ Command |
+ Description |
+
+
+ add number |
+ Adds the number to the internal state. The number must be a decimal integer. The successful response will contain the new state. |
+
+
+ reset |
+ Resets the connection state to zero. |
+
+
+ count |
+ The successful response returns the number of open connections instead of the state. |
+
+
+ close |
+ Closes the connection. There is no response on success. |
+
+
+ quit |
+ Exits the entire system. There is no response on success. |
+
+
+
+Responses
+
+Responses always start with ok for successful commands or error for indicating problems.
+
+
+
+ Response |
+ Description |
+
+
+ ok number |
+ The command was successful. The number contains the current state or (after count) the number of connections. |
+
+
+ error nan |
+ The parameter was not a number. |
+
+
+ error param |
+ The number of parameter was not correct. |
+
+
+ error command |
+ The command was not understood. |
+
+
+ error nocommand |
+ There 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