Dabei handelt es sich um gensio (ausgesprochen gen'-see-oh), ein Framework zur Bereitstellung einer konsistenten Ansicht verschiedener Stream- (und Paket-) I/O-Typen. Sie erstellen ein Gensio-Objekt (oder ein Gensio) und können dieses Gensio verwenden, ohne zu viel darüber wissen zu müssen, was darunter vor sich geht. Sie können Gensio übereinander stapeln, um Protokollfunktionalität hinzuzufügen. Sie können beispielsweise ein TCP-Gensio erstellen, darauf SSL und darauf Telnet stapeln. Es unterstützt eine Reihe von Netzwerk-E/A- und seriellen Ports. Es unterstützt auch Soundschnittstellen. Gensios, die auf anderen Gensios gestapelt sind, werden Filter genannt.
Dasselbe können Sie auch mit den Empfangsports machen. Sie können einen Gensio-Akzeptor einrichten, um Verbindungen in einem Stapel zu akzeptieren. In unserem vorherigen Beispiel können Sie also TCP so einrichten, dass es einen bestimmten Port überwacht und automatisch SSL und Telnet an die erste Stelle setzt, wenn die Verbindung zustande kommt, und Sie werden erst informiert, wenn alles bereit ist.
gensio funktioniert unter Linux, BSDs, MacOS und Windows. Unter Windows erhalten Sie eine Single-Thread-fähige (aber auch Multi-Thread-fähige) ereignisgesteuerte Schnittstelle (mit verfügbaren Blockierungsschnittstellen), um die Programmierung mit vielen I/Os zu vereinfachen. Dies trägt erheblich dazu bei, das Schreiben von portablem E/A-gesteuertem Code zu vereinfachen.
Ein sehr wichtiges Merkmal von Gensio ist, dass es den Aufbau verschlüsselter und authentifizierter Verbindungen viel einfacher macht als ohne Gensio. Über die grundlegende Schlüsselverwaltung hinaus ist es wirklich nicht schwieriger als TCP oder irgendetwas anderes. Es bietet bei Bedarf erweiterte Flexibilität zur Steuerung des Authentifizierungsprozesses. Es ist wirklich einfach zu bedienen.
Beachten Sie, dass die Manpage zu gensio(5) weitere Details zu einzelnen Gensio-Typen enthält.
Anweisungen zum Erstellen aus dem Quellcode finden Sie im Abschnitt „Erstellen“ am Ende.
Es gibt einige Tools, die gensios nutzen, sowohl als Beispiel als auch zum Ausprobieren. Diese sind:
Ein SSHD-ähnlicher Daemon, der Certauth, SSL und SCTP- oder TCP-Gensios zum Herstellen von Verbindungen verwendet. Es verwendet die Standard-PAM-Authentifizierung und verwendet PTYS. Weitere Informationen finden Sie unter gtlsshd(8).
In FAQ.rst gibt es einen Punkt mit dem Namen „So führen Sie gtlsshd unter Windows aus“. Weitere Einzelheiten finden Sie dort und im Abschnitt „Auf Windows aufbauen“ weiter unten, da es ein paar knifflige Dinge gibt, mit denen Sie umgehen müssen.
Folgende Bücher stehen in der Bibliothek zur Verfügung:
Ein Gensio-Akzeptor, der einen Gensio-Stack-String als Parameter akzeptiert. Dadurch können Sie einen Gensio als Akzeptor verwenden. Wenn Conacc gestartet wird, öffnet es das Gensio, und wenn das Gensio geöffnet wird, meldet es ein neues untergeordnetes Element für den Akzeptanten. Wenn das untergeordnete Element geschlossen wird, versucht es, das untergeordnete Element erneut zu öffnen und den Vorgang erneut durchzuführen (es sei denn, die Annahme wurde bei conacc deaktiviert).
Warum sollten Sie das nutzen? Angenommen, Sie möchten in ser2net einen seriellen Port mit einem anderen verbinden. Sie könnten eine Verbindung haben wie:
connection : &con0
accepter : conacc,serialdev,/dev/ttyS1,115200
connector : serialdev,/dev/ttyS2,115200
Und es würde /dev/ttyS1 mit /dev/ttyS2 verbinden. Ohne conacc könnten Sie serialdev nicht als Akzeptor verwenden. Damit können Sie gtlsshd auch an einem seriellen Port verwenden, wenn Sie verschlüsselte, authentifizierte Anmeldungen über einen seriellen Port wünschen. Wenn Sie gtlsshd mit Folgendem ausgeführt haben:
gtlsshd --notcp --nosctp --oneshot --nodaemon --other_acc
' conacc,relpkt(mode=server),msgdelim,/dev/ttyUSB1,115200n81 '
Sie könnten eine Verbindung herstellen mit:
gtlssh --transport ' relpkt,msgdelim,/dev/ttyUSB2,115200n81 ' USB2
Dadurch entsteht ein zuverlässiger Pakettransport über eine serielle Schnittstelle. Der Modus=Server ist erforderlich, damit relpkt als Server ausgeführt wird, da es normalerweise als Client ausgeführt wird, da es nicht als Akzeptor gestartet wird. Das SSL-Gensio (das über den Transport läuft) erfordert eine zuverlässige Kommunikation und läuft daher nicht direkt über einen seriellen Port.
Ja, es sieht aus wie ein Durcheinander von Buchstaben.
Ein Filtergensio, das auf dem Tongensio sitzt und ein Audio Frequency Shift Keying-Modem ausführt, wie es beim AX.25-Amateurfunk verwendet wird.
Ein Amateurfunkprotokoll für Paketfunk. Um dies vollständig zu nutzen, müssten Sie Code schreiben, da es Kanäle und OOB-Daten für nicht nummerierte Informationen verwendet. Sie können jedoch grundlegende Dinge nur mit Gensiot erledigen, wenn Sie nur einen Kommunikationskanal benötigen. Wenn Sie beispielsweise mit jemandem über Funk chatten möchten und der Kiss-Port auf beiden Rechnern auf 8001 steht, können Sie auf dem akzeptierenden Rechner Folgendes ausführen:
gensiot -i ' stdio(self) ' -a
' ax25(laddr=AE5KM-1),kiss,conacc,tcp,localhost,8001 '
Dieser verbindet sich mit dem TNC und wartet auf eine Verbindung an der Adresse AE5KM-1. Dann könnten Sie Folgendes ausführen:
gensiot -i ' stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,AE5KM-1,AE5KM-2"),kiss,tcp,localhost,8001 '
auf der anderen Maschine. Dadurch wird über TNC 0 mit der angegebenen Adresse eine Verbindung zum anderen Computer hergestellt. Dann erscheint alles, was Sie in das eine eingeben, zeilenweise auf dem anderen. Geben Sie zum Beenden „Strg-D“ ein. Der „stdio(self)“-Teil schaltet den Raw-Modus aus, sodass es eine Zeile nach der anderen ist und Sie ein lokales Echo erhalten. Andernfalls würde jedes von Ihnen eingegebene Zeichen ein Paket senden und Sie könnten nicht sehen, was Sie eingeben.
Um eine Verbindung zum N5COR-11 AX.25 BBS-System herzustellen, gehen Sie wie folgt vor:
gensiot -i ' xlt(nlcr),stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,N5COR-11,AE5KM-2"),kiss,tcp,localhost,8001 '
Die meisten BBS-Systeme verwenden CR und nicht NL für die neue Zeile, daher wird das XLT-Gensio verwendet, um eingehende Zeichen zu übersetzen.
Da es sich hierbei um Gensio handelt, können Sie natürlich jedes funktionsfähige Gensio unter Ax25 platzieren, das Sie möchten. Wenn Sie also ohne Radio herumspielen oder testen möchten, können Sie ax25 über UDP-Multicast ausführen. Hier ist die Akzeptorseite:
gensiot -i ' stdio(self) ' -a
' ax25(laddr=AE5KM-1),conacc, '
' udp(mcast="ipv4,224.0.0.20",laddr="ipv4,1234",nocon), '
' ipv4,224.0.0.20,1234 '
und hier ist die Steckerseite:
gensiot -i ' stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,AE5KM-1,AE5KM-2"), '
' udp(mcast="ipv4,224.0.0.20",laddr="ipv4,1234",nocon), '
' ipv4,224.0.0.20,1234 '
Kiss ist nicht erforderlich, da UDP bereits ein paketorientiertes Medium ist. Oder Sie erstellen mit dem Programm greflector eine simulierte Funksituation. Führen Sie auf der Maschine „radiopi2“ Folgendes aus:
greflector kiss,tcp,1234
Dadurch wird ein Programm erstellt, das alle empfangenen Eingaben an alle anderen Verbindungen weiterleitet. Dann auf der Akzeptorseite:
gensiot -i ' stdio(self) ' -a
' ax25(laddr=AE5KM-1),kiss,conacc,tcp,radiopi2,1234 '
und die Verbindungsseite:
gensiot -i ' stdio(self) '
' ax25(laddr=AE5KM-2,addr="0,AE5KM-1,AE5KM-2"),kiss,tcp,radiopi2,1234 '
Der Testcode verwendet den Reflektor für einige Tests, da er so bequem zu verwenden ist.
Diese sind alle ausführlich in gensio(5) dokumentiert. Sofern nicht anders angegeben, sind diese alle als Akzeptoren oder Verbindungsgensios verfügbar.
Sie können Ihre eigenen Gensios erstellen, diese in der Bibliothek registrieren und zusammen mit den anderen Gensios stapeln.
Der einfachste Weg, dies zu tun, besteht darin, Code von einem Gensio zu stehlen, der genau das tut, was Sie wollen, und ihn dann zu ändern, um Ihr eigenes Gensio zu erstellen. Leider gibt es keine gute Dokumentation dazu.
Die Include-Datei include/gensio/gensio_class.h verfügt über die Schnittstelle zwischen der Haupt-Gensio-Bibliothek und dem Gensio. Die Gensio-Aufrufe erfolgen alle über eine einzige Funktion mit Nummern zur Identifizierung der angeforderten Funktion. Sie müssen all dies den tatsächlichen Vorgängen zuordnen. Das ist etwas mühsam, erleichtert aber die Vorwärts- und Abwärtskompatibilität erheblich.
Auf diese Weise ein eigenes Gensio zu erstellen, ist ziemlich komplex. Der Zustandsautomat für so etwas kann überraschend komplex sein. Das Aufräumen ist der schwierigste Teil. Sie müssen sicherstellen, dass Sie keine Rückrufe mehr haben und beim Herunterfahren möglicherweise keine Timer in einer Race-Bedingung zurückgerufen werden. Nur die einfachsten Gensios (echo, dummy), seltsame Gensios (conadd, keepopen, stdio) und Gensios mit Kanälen (mux, ax25) implementieren die Schnittstelle direkt. Alles andere verwendet include/gensio/gensio_base.h. gensio_base stellt die grundlegende Zustandsmaschine für ein Gensio bereit. Es verfügt über einen Filterteil (der optional ist) und einen Low-Level-Teil (II), der dies nicht ist.
Die Filterschnittstelle wird von Daten zur Verarbeitung durchlaufen. Dies wird für Dinge wie SSL, Certauth, Ratelimit usw. verwendet. Filter Gensios würden dies verwenden. Diese verwenden alle gensio_ll_gensio (zum Stapeln eines Gensio auf einem anderen Gensio) für die ll.
Terminalgensios haben jeweils ihre eigene Fülle und im Allgemeinen keinen Filter. Für lls, die auf einem Dateideskriptor (fd) basieren, wird gensio_ll_fd verwendet. Es gibt auch eine Version für IPMI Serial-over-LAN (ipmisol) und für Sound. Die meisten Terminalgensios (TCP, UDP, SCTP, serielle Schnittstelle, PTY) verwenden offensichtlich die fd ll.
Sobald Sie ein Gensio haben, können Sie es als Modul kompilieren und in $(moduleinstalldir)/<version> einfügen. Dann wird der Gensio es einfach aufheben und verwenden. Sie können es auch mit Ihrer Anwendung verknüpfen und die Init-Funktion von Ihrer Anwendung aus ausführen.
Der mdns gensio wurde bereits besprochen, aber die gensio-Bibliothek bietet eine einfach zu verwendende mDNS-Schnittstelle. Die Include-Datei dafür befindet sich in gensio_mdns.h, und Sie können die Manpage gensio_mdns(3) verwenden, um weitere Informationen dazu zu erhalten.
Um eine MDNS-Verbindung mit Gensiot herzustellen, nehmen wir an, dass Sie ser2net mit aktiviertem MDNS eingerichtet haben, etwa so:
connection : &my-port
accepter : telnet(rfc2217),tcp,3001
connector : serialdev,/dev/ttyUSB1,115200N81
options :
mdns : true
Dann können Sie mit Gensiot eine Verbindung herstellen:
gensiot ' mdns,my-port '
Gensiot findet den Server, den Port und ob Telnet und RFC2217 aktiviert sind, und stellt die Verbindung her.
Darüber hinaus gibt es ein gmdns-Tool, mit dem Sie Abfragen und Werbung durchführen können, und gtlssh kann mDNS-Abfragen durchführen, um Dienste zu finden. Wenn Sie über sichere authentifizierte Anmeldungen für ser2net verfügen und mdns auf ser2net aktivieren, wie zum Beispiel:
connection : &access-console
accepter : telnet(rfc2217),mux,certauth(),ssl,tcp,3001
connector : serialdev,/dev/ttyUSBaccess,115200N81
options :
mdns : true
Dies macht die Einrichtung sehr komfortabel, da Sie einfach Folgendes tun können:
gtlssh -m access-console
Das ist richtig, Sie können einfach direkt den Verbindungsnamen verwenden, ohne den Host zu kennen, weder Telnet oder RFC2217 zu kennen noch den Port zu kennen. Sie müssen die Schlüssel usw. natürlich noch gemäß dieser Anleitung auf dem ser2net-Server einrichten.
gensio verfügt über eine objektorientierte Schnittstelle, die ereignisgesteuert ist. Es sind auch synchrone Schnittstellen verfügbar. In Gensio haben Sie es mit zwei Hauptobjekten zu tun: einem Gensio und einem Gensio-Akzeptor. Ein Gensio bietet eine Kommunikationsschnittstelle, über die Sie eine Verbindung herstellen, trennen, schreiben, empfangen usw. können.
Mit einem Gensio-Accepter können Sie eingehende Verbindungen empfangen. Wenn eine Verbindung zustande kommt, erhalten Sie einen Gensio.
Die Schnittstelle ist ereignisgesteuert, da sie größtenteils völlig nicht blockierend ist. Wenn Sie ein Gensio öffnen, geben Sie ihm einen Rückruf, der aufgerufen wird, wenn die Verbindung besteht oder die Verbindung fehlschlägt. Das Gleiche gilt für die Nähe. Ein Schreibvorgang gibt die Anzahl der akzeptierten Bytes zurück, es werden jedoch möglicherweise nicht alle Bytes (oder sogar einige der Bytes) verwendet, und der Aufrufer muss dafür verantwortlich sein.
Die Öffnungs- und Schließschnittstellen verfügen aus praktischen Gründen über eine sekundäre Blockierungsschnittstelle. Diese enden auf _s. Dies dient der Bequemlichkeit, ist aber nicht notwendig und Sie müssen bei der Verwendung vorsichtig sein, da Sie sie bei Rückrufen nicht wirklich verwenden können.
Apropos Rückrufe, Daten und Informationen, die von Gensio an den Benutzer gelangen, werden mit einem Funktionsrückruf erledigt. Daten werden gelesen, und wenn der Gensio zum Schreiben von Daten bereit ist, erfolgt ein Rückruf. Eine ähnliche Schnittstelle wird für den Aufruf des Benutzers an die Gensio-Ebene verwendet, ist jedoch für den Benutzer verborgen. Diese Art von Schnittstelle ist leicht erweiterbar, neue Vorgänge können problemlos hinzugefügt werden, ohne dass alte Schnittstellen beschädigt werden.
Die Bibliothek bietet mehrere Möglichkeiten zum Erstellen eines Gensio oder Gensio-Akzeptors. Der Hauptweg ist str_to_gensio() und str_to_gensio_accepter(). Diese bieten eine Möglichkeit, einen Stapel von Gensios oder Akzeptoren als String und Build anzugeben. Im Allgemeinen sollten Sie diese Schnittstelle verwenden, wenn Sie können.
Im Allgemeinen sind Schnittstellen, die nicht leistungsabhängig sind, stringbasiert. Sie sehen dies in gensio_control und in Hilfsdaten in der Lese- und Schreibschnittstelle, um bestimmte Aspekte des Schreibvorgangs zu steuern.
Die Bibliothek bietet auch Möglichkeiten, Ihre Gensios einzurichten, indem Sie jedes einzelne einzeln erstellen. In manchen Situationen kann dies notwendig sein, aber es schränkt die Möglichkeit ein, neue Funktionen der Gensio-Bibliothek zu nutzen, wenn diese erweitert wird.
Wenn ein Gensio mehrere Streams unterstützt (wie SCTP), werden Stream-Nummern in den Auxdata mit „stream=n“ übergeben. Streams werden nicht einzeln flussgesteuert.
Kanäle hingegen sind separate Datenflüsse über dieselbe Verbindung. Kanäle werden als separate Gensios dargestellt und können individuell flussgesteuert werden.
Es gibt einige Include-Dateien, mit denen Sie möglicherweise umgehen müssen, wenn Sie Gensios verwenden:
Diese sind größtenteils in den Manpages dokumentiert.
Für die Erstellung eigener Gensios stehen Ihnen folgende Include-Dateien zur Verfügung:
Jede Include-Datei enthält umfangreiche Dokumentation zu den einzelnen Aufrufen und Handlern.
gensio verfügt über einen eigenen Fehlersatz, um ihn von den Betriebssystemfehlern zu abstrahieren (genannt GE_xxx) und mehr Flexibilität bei der Fehlerberichterstattung zu bieten. Diese befinden sich in der Include-Datei gensio_err.h (automatisch aus gensio.h eingebunden) und können mit gensio_err_to_str() von Zahlen in eine aussagekräftige Zeichenfolge übersetzt werden. Null ist definiert als kein Fehler.
Wenn ein unerkannter Betriebssystemfehler auftritt, wird GE_OSERR zurückgegeben und ein Protokoll über die Betriebssystem-Handler-Protokollschnittstelle gemeldet.
Eine etwas ärgerliche Sache an Gensio ist, dass Sie einen Betriebssystem-Handler (struct gensio_os_funcs) bereitstellen müssen, um Betriebssystem-artige Funktionen wie Speicherzuweisung, Mutexe, die Fähigkeit, Dateideskriptoren, Timer und Zeit zu verarbeiten, und einige andere Dinge zu verwalten.
Die Bibliothek stellt mehrere Betriebssystem-Handler bereit. Sie können gensio_alloc_os_funcs() aufrufen, um Ihrem System (POSIX oder Windows) einen Standardwert zuzuweisen. Weitere Einzelheiten finden Sie auf dieser Manpage. Dies ist im Allgemeinen die leistungsstärkste Option, die Sie für Ihr System haben.
Für POSIX-Systeme stehen OS-Handler für Glib und TCL zur Verfügung, zugewiesen mit gensio_glib_funcs_alloc() und gensio_tcl_funcs_alloc(). Diese funktionieren wirklich nicht besonders gut, insbesondere aus Leistungssicht. Die APIs für Glib und TCL sind nicht gut für die Funktionen von Gensio ausgelegt. TCL kann nur Single-Threaded-Betrieb unterstützen. Bei der Glib-Multithread-Operation wartet jeweils nur ein Thread auf E/A. Aber sie funktionieren, und die Tests werden mit ihnen durchgeführt. Diese sind unter Windows aufgrund schlechter Abstraktionen bei Glib und mangelnder Motivation bei TCL nicht verfügbar.
Wenn Sie jedoch etwas anderes wie X Windows usw. verwenden, das über eine eigene Ereignisschleife verfügt, müssen Sie möglicherweise eine an Ihre Bedürfnisse anpassen. Aber das Gute daran ist, dass Sie dies tun und Gensio in so ziemlich alles integrieren können.
Es gibt auch eine Waiter-Schnittstelle, die eine bequeme Möglichkeit bietet, auf Ereignisse zu warten, während die Ereignisschleife ausgeführt wird. Auf diese Weise gelangen Sie im Allgemeinen in die Ereignisschleife, da Sie so bequem signalisieren können, wenn Sie fertig sind und die Schleife verlassen müssen.
Die Dokumentation dazu finden Sie in:
include/gensio/gensio_os_funcs.h
Die Gensio-Bibliothek unterstützt Threads vollständig und ist vollständig Thread-sicher. Es verwendet jedoch Signale auf POSIX-Systemen und COM auf Windows-Systemen, sodass einige Einstellungen erforderlich sind.
Der „Haupt“-Thread sollte beim Start gensio_os_proc_setup() aufrufen und nach Abschluss gensio_os_proc_cleanup() aufrufen. Dadurch werden Signale und Signalhandler, lokaler Thread-Speicher unter Windows und andere Dinge eingerichtet.
Mit gensio_os_new_thread() können Sie neue Threads aus einem bereits eingerichteten Thread erzeugen. Dadurch erhalten Sie einen grundlegenden Betriebssystem-Thread und sind ordnungsgemäß für Gensio konfiguriert.
Wenn Sie einen Thread auf andere Weise erstellt haben, den Sie in Gensio verwenden möchten, solange der Thread einen anderen Thread erstellt und keine blockierenden Funktionen ausführt (jede Art von Wartevorgang, Hintergrundverarbeitung, Funktionen, die auf _s enden, wie read_s, usw.) müssen Sie nicht einrichten. Auf diese Weise kann ein externer Thread Daten schreiben, einen anderen Thread aktivieren oder ähnliche Dinge tun.
Wenn ein externer Thread diese Dinge tun muss, sollte er gensio_os_thread_setup() aufrufen.
Wie im Thread-Abschnitt erwähnt, verwendet die Gensio-Bibliothek unter Unix Signale für Inter-Thread-Wakeups. Ich habe genau hingesehen, und es gibt wirklich keine andere Möglichkeit, das sauber zu machen. Aber Windows hat auch ein paar signalähnliche Dinge, und diese sind auch in Gensio verfügbar.
Wenn Sie gensio_alloc_os_funcs() verwenden, erhalten Sie eine Betriebssystemfunktion, die das übergebene Signal für IPC verwendet. Sie können GENSIO_OS_FUNCS_DEFAULT_THREAD_SIGNAL für das Signal übergeben, wenn Sie den Standardwert SIGUSR1 wünschen. Das von Ihnen verwendete Signal wird von gensio blockiert und übernommen, Sie können es nicht verwenden.
Gensio bietet auch eine generische Handhabung für einige Signale. Unter Unix wird SIGHUP über die Funktion gensio_os_proc_register_reload_handler() verarbeitet.
Unter Windows und Unix können Sie gensio_os_proce_register_term_handler() verwenden, das Beendigungsanforderungen verarbeitet (SIGINT, SIGTERM, SIGQUIT unter Unix) und gensio_os_proc_register_winsize_handler() (SIGWINCH unter Unix). Wie diese über Windows eingehen, ist etwas chaotischer, aber für den Benutzer unsichtbar.
Alle Rückrufe stammen aus dem Wartezustand einer Warteroutine, nicht vom Signalhandler. Das sollte Ihr Leben erheblich vereinfachen.
Weitere Einzelheiten hierzu finden Sie in den Manpages.
Um ein Gensio zu erstellen, besteht die allgemeine Vorgehensweise darin, str_to_gensio()
mit einer ordnungsgemäß formatierten Zeichenfolge aufzurufen. Die Zeichenfolge ist wie folgt formatiert:
<Typ>[([<Option>[,<Option[...]]])][,<Typ>...][,<Endoption>[,<Endoption>]]
Die end option
ist für Terminal-Gensios oder solche, die sich am Ende des Stapels befinden. Beispielsweise erstellt tcp,localhost,3001
ein Gensio, das eine Verbindung zu Port 3001 auf localhost herstellt. Ein Beispiel für einen seriellen Port ist serialdev,/dev/ttyS0,9600N81
stellt eine Verbindung zum seriellen Port /dev/ttyS0 her.
Dadurch können Sie Gensio-Ebenen über Gensio-Ebenen stapeln. Um beispielsweise Telnet über eine TCP-Verbindung zu legen:
telnet,tcp,localhost,3001
Angenommen, Sie möchten RFC2217 für Ihre Telnet-Verbindung aktivieren. Sie können dazu eine Option hinzufügen:
telnet(rfc2217=true),tcp,localhost,3001
Wenn Sie ein Gensio erstellen, stellen Sie einen Callback mit Benutzerdaten bereit. Wenn Ereignisse auf einem Gensio auftreten, wird der Rückruf aufgerufen, damit der Benutzer damit umgehen kann.
Ein Gensio-Akzeptor ähnelt einem verbindenden Gensio, verfügt jedoch stattdessen über str_to_gensio_accepter()
. Das Format ist das gleiche. Zum Beispiel:
telnet(rfc2217=true),tcp,3001
erstellt einen TCP-Akzeptor mit Telnet an der Spitze. Für Akzeptoren müssen Sie im Allgemeinen nicht den Hostnamen angeben, wenn Sie eine Bindung an alle Schnittstellen auf dem lokalen Computer herstellen möchten.
Sobald Sie ein Gensio erstellt haben, ist es noch nicht geöffnet oder betriebsbereit. Um es zu verwenden, müssen Sie es öffnen. Um es zu öffnen, gehen Sie wie folgt vor:
struct gensio * io ;
int rv ;
rv = str_to_gensio ( "tcp,localhost,3001" , oshnd ,
tcpcb , mydata , & io );
if ( rv ) { handle error }
rv = gensio_open ( io , tcp_open_done , mydata );
if ( rv ) { handle error }
Beachten Sie, dass bei der Rückkehr gensio_open()
das Gensio nicht geöffnet ist. Sie müssen warten, bis der Rückruf (in diesem Fall tcp_open_done()
) aufgerufen wird. Danach können Sie es verwenden.
Sobald das Gensio geöffnet ist, erhalten Sie nicht sofort Daten darauf, da der Empfang deaktiviert ist. Sie müssen gensio_set_read_callback_enable()
aufrufen, um ein- und auszuschalten, ob der Rückruf (in diesem Fall tcpcb
) aufgerufen wird, wenn Daten empfangen werden.
Wenn der Lesehandler aufgerufen wird, werden der Puffer und die Länge übergeben. Sie müssen nicht alle Daten verarbeiten, wenn dies nicht möglich ist. Sie müssen den Buflen mit der Anzahl der tatsächlich verarbeiteten Bytes aktualisieren. Wenn Sie keine Daten verarbeiten, werden die nicht verarbeiteten Daten im Gensio für später zwischengespeichert. Wenn Sie nicht alle Daten verarbeiten, sollten Sie die Lesefreigabe nicht deaktivieren, da sonst das Ereignis sofort erneut aufgerufen wird.
Wenn bei einer Verbindung etwas schief geht, wird der Lesehandler mit einem Fehlersatz aufgerufen. buf
und buflen
sind in diesem Fall NULL.
Zum Schreiben können Sie gensio_write()
aufrufen, um Daten zu schreiben. Sie können gensio_write()
jederzeit auf einem offenen Gensio verwenden. gensio_write()
übernimmt möglicherweise nicht alle Daten, die Sie darauf schreiben. Der count
Parameter gibt die Anzahl der beim Schreibaufruf tatsächlich belegten Bytes zurück.
Sie können Ihren Code so gestalten, dass er gensio_set_write_callback_enable()
aufruft, wenn Sie Daten senden müssen, und der Gensio den „Schreibbereit“-Rückruf aufruft und Sie aus dem Rückruf schreiben können. Dies ist im Allgemeinen einfacher, aber das Aktivieren und Deaktivieren des Schreibrückrufs erhöht den Mehraufwand.
Ein effizienterer Ansatz besteht darin, Daten bei Bedarf zu schreiben und den Schreibrückruf zu deaktivieren. Wenn der Schreibvorgang weniger als die vollständige Anfrage zurückgibt, hat das andere Ende die Flusskontrolle aktiviert und Sie sollten den Schreibrückruf aktivieren und warten, bis er aufgerufen wird, bevor Sie weitere Daten senden.
In den Rückrufen können Sie die Benutzerdaten abrufen, die Sie mit gensio_get_user_data()
an den Erstellungsaufruf übergeben haben.
Beachten Sie, dass das in Ordnung ist, wenn Sie ein Gensio öffnen und dann sofort schließen, auch wenn der Open-Callback nicht aufgerufen wurde. Der offene Rückruf kann in diesem Fall jedoch aufgerufen werden oder auch nicht, so dass es schwierig sein kann, dies richtig zu handhaben.
Mit Gensios können Sie grundlegende synchrone E/A durchführen. Dies ist in manchen Situationen nützlich, in denen Sie etwas inline lesen müssen. Rufen Sie dazu an:
err = gensio_set_sync ( io );
Das angegebene Gensio wird keine Lese- und Schreibereignisse mehr liefern. Weitere Veranstaltungen werden ausgeliefert. Dann können Sie Folgendes tun:
err = gensio_read_s ( io , & count , data , datalen , & timeout );
err = gensio_write_s ( io , & count , data , datalen , & timeout );
Count wird auf die tatsächliche Anzahl der gelesenen/geschriebenen Bytes gesetzt. Es kann NULL sein, wenn es Ihnen egal ist (obwohl das beim Lesen nicht viel Sinn macht).
Timeout kann NULL sein, wenn ja, dann ewig warten. Wenn Sie eine Zeitüberschreitung festlegen, wird diese auf die verbleibende Zeit aktualisiert.
Beachten Sie, dass Signale dazu führen, dass diese sofort zurückkehren, es wird jedoch kein Fehler gemeldet.
Lesevorgänge werden blockiert, bis einige Daten eingehen, und diese Daten werden zurückgegeben. Es wird nicht gewartet, bis der Puffer voll ist. timeout ist ein Zeitwert. Der Lesevorgang wartet so lange, bis der Lesevorgang abgeschlossen ist und zurückkehrt. Ein Timeout ist kein Fehler, der Zähler wird lediglich auf Null gesetzt.
Schreibt den Block, bis der gesamte Puffer geschrieben ist oder ein Timeout auftritt. Auch hier handelt es sich bei der Zeitüberschreitung nicht um einen Fehler, sondern es werden die insgesamt tatsächlich geschriebenen Bytes als Anzahl zurückgegeben.
Wenn Sie mit der synchronen E/A mit einem Gensio fertig sind, rufen Sie Folgendes auf:
err = gensio_clear_sync ( io );
und die Zustellung über die Event-Schnittstelle wird wie bisher fortgesetzt. Sie dürfen sich beim Aufruf nicht in einem synchronen Lese- oder Schreibaufruf befinden, da die Ergebnisse undefiniert sind.
Beachten Sie, dass andere E/A-Vorgänge auf anderen Gensios weiterhin auftreten, wenn auf synchrone E/A-Vorgänge gewartet wird
Derzeit gibt es keine Möglichkeit, mit synchroner E/A auf mehrere Gensios zu warten. Wenn Sie das tun, sollten Sie eigentlich nur die ereignisgesteuerte E/A verwenden. Es ist effizienter und am Ende macht man sowieso das Gleiche.
Wie ein Gensio ist ein Gensio-Akzeptor nicht betriebsbereit, wenn Sie ihn erstellen. Sie müssen gensio_acc_startup()
aufrufen, um es zu aktivieren:
struct gensio_accepter * acc ;
int rv ;
rv = str_to_gensio_accepter ( "tcp,3001" , oshnd ,
tcpacccb , mydata , & acc );
if ( rv ) { handle error }
rv = gensio_startup ( acc );
if ( rv ) { handle error }
Beachten Sie, dass es keinen Rückruf zum Startaufruf gibt, um zu erfahren, wann er aktiviert ist, da dies nicht wirklich erforderlich ist, da Sie nicht darauf schreiben können, sondern nur Rückrufe ausführen.
Selbst nachdem Sie den Accepter gestartet haben, wird er nichts unternehmen, bis Sie gensio_acc_set_accept_callback_enable()
aufrufen, um diesen Rückruf zu aktivieren.
Wenn der Rückruf aufgerufen wird, erhalten Sie einen Gensio im data
, der bereits mit deaktiviertem Lesen geöffnet ist. Ein von einem Gensio-Akzeptor empfangenes Gensio kann einige Einschränkungen aufweisen. Beispielsweise können Sie es möglicherweise nicht schließen und dann erneut öffnen.
Gensio-Akzeptanten können synchrone Annahmen mit gensio_acc_set_sync()
und gensio_acc_accept_s
durchführen. Weitere Informationen finden Sie in den entsprechenden Manpages.
struct gensio_os_funcs
verfügt über einen Vlog-Rückruf für die Verarbeitung interner Gensio-Protokolle. Diese werden aufgerufen, wenn etwas Wichtiges passiert, Gensio jedoch keine Möglichkeit hat, einen Fehler zu melden. Es kann auch aufgerufen werden, um die Diagnose eines Problems zu erleichtern, wenn etwas schief geht.
Die Gensio- und Gensio-Accepter-Klassen verfügen jeweils über Unterklassen für die Verarbeitung serieller E/A und das Festlegen aller mit einem seriellen Port verbundenen Parameter.
Sie können herausfinden, ob ein Gensio (oder eines seiner Kinder) ein serieller Port ist, indem Sie gensio_to_sergensio()
aufrufen. Wenn dies NULL zurückgibt, ist es kein Sergensio und keines seiner untergeordneten Elemente ist Sergensios. Wenn es einen Wert ungleich NULL zurückgibt, gibt es das Sergensio-Objekt zurück, das Sie verwenden können. Beachten Sie, dass der von sergensio_to_gensio()
zurückgegebene Gensio derjenige ist, der an gensio_to_sergensio()
übergeben wird, und nicht unbedingt der Gensio, mit dem sergensio direkt verknüpft ist.
Ein Sergensio kann ein Client sein, was bedeutet, dass er serielle Einstellungen festlegen kann, oder er kann ein Server sein, was bedeutet, dass er serielle Einstellungen vom anderen Ende der Verbindung empfängt.
Die meisten Sergensios sind nur Clients: Serialdev (normaler serieller Port), Ipmisol und Stdio Accepter. Derzeit verfügt nur Telnet über Client- und Serverfunktionen.
HINWEIS: Die hier beschriebene Python-Schnittstelle ist veraltet. Verwenden Sie jetzt das in c++/swig/pygensio.
Sie können über Python auf nahezu die gesamte Gensio-Schnittstelle zugreifen, allerdings erfolgt dies etwas anders als bei der C-Schnittstelle.
Da Python vollständig objektorientiert ist, sind Gensios und Gensio-Akzeptanten neben gensio_os_funcs, sergensios und waiters erstklassige Objekte.
Hier ist ein kleines Programm:
import gensio
class Logger :
def gensio_log ( self , level , log ):
print ( "***%s log: %s" % ( level , log ))
class GHandler :
def __init__ ( self , o , to_write ):
self . to_write = to_write
self . waiter = gensio . waiter ( o )
self . readlen = len ( to_write )
def read_callback ( self , io , err , buf , auxdata ):
if err :
print ( "Got error: " + err )
return 0
print ( "Got data: " + buf );
self . readlen -= len ( buf )
if self . readlen == 0 :
io . read_cb_enable ( False )
self . waiter . wake ()
return len ( buf )
def write_callback ( self , io ):
print ( "Write ready!" )
if self . to_write :
written = io . write ( self . to_write , None )
if ( written >= len ( self . to_write )):
self . to_write = None
io . write_cb_enable ( False )
else :
self . to_write = self . to_write [ written :]
else :
io . write_cb_enable ( False )
def open_done ( self , io , err ):
if err :
print ( "Open error: " + err );
self . waiter . wake ()
else :
print ( "Opened!" )
io . read_cb_enable ( True )
io . write_cb_enable ( True )
def wait ( self ):
self . waiter . wait_timeout ( 1 , 2000 )
o = gensio . alloc_gensio_selector ( Logger ())
h = GHandler ( o , "This is a test" )
g = gensio . gensio ( o , "telnet,tcp,localhost,2002" , h )
g . open ( h )
h . wait ()
Die Schnittstelle ist eine ziemlich direkte Übersetzung der C-Schnittstelle. Eine Python-Darstellung der Schnittstelle befindet sich in swig/python/gensiodoc.py. Sie können diese zur Dokumentation einsehen.
Die C++-Schnittstelle ist in c++/README.rst dokumentiert.
Die neue Pygensio-Schnittstelle ist eine sauberere Implementierung, die Swig-Direktoren anstelle von handcodierten Rückrufen in Python verwendet. Siehe README.rst in c++/swig/pygensio. Es gibt auch glib- und tcl-OS_Funcs in den glib- und tcl-Verzeichnissen.
Die vollständige C++-Schnittstelle steht Go-Programmen über swig und swig Directors zur Verfügung. Weitere Informationen finden Sie unter c++/swig/go/README.rst.
Dies ist ein normales Autoconf-System, nichts Besonderes. Beachten Sie, dass die Build-Infrastruktur nicht enthalten ist, wenn Sie dies direkt von Git erhalten. Im Hauptverzeichnis gibt es ein Skript namens „reconf“, das es für Sie erstellt.
Wenn Sie sich mit Autoconf nicht auskennen, finden Sie in der INSTALL-Datei einige Informationen oder googeln Sie sie.
Um Gensio vollständig zu erstellen, benötigen Sie Folgendes:
Im Folgenden wird alles außer openipmi auf Ubuntu 20.04 eingerichtet:
- sudo apt install gcc g++ git swig python3-dev libssl-dev pkg-config
- libavahi-client-dev avahi-daemon libtool autoconf automake make libsctp-dev libpam-dev libwrap0-dev libglib2.0-dev tcl-dev libasound2-dev libudev-dev
Unter Redhat gibt es libwrap nicht mehr, sodass Sie es nicht verwenden werden, und swig scheint nicht verfügbar zu sein, sodass Sie es selbst mit mindestens Go- und Python-Unterstützung erstellen müssen. Hier ist der Befehl für Redhat-ähnliche Systeme:
- sudo yum install gcc gcc-c++ git python3-devel swig openssl-devel
- PKG-Konfig
Möglicherweise müssen Sie Folgendes ermöglichen, um den Zugriff auf die Entwicklungspakete zu ermöglichen:
sudo dnf config-Manager-set-fähige Entwicklung
Und holen Sie sich die SCTP -Kernel -Module, vielleicht müssen Sie dies tun:
sudo yum installieren kernelmodules-extra
Um die GO -Sprache zu verwenden, müssen Sie eine Version von Swig 4.1.0 oder mehr erhalten. Möglicherweise müssen Sie eine Blutungsrandversion aus Git herausziehen und diese verwenden.
Die Umgang mit Python -Installationskonfiguration ist ein wenig Schmerz. Standardmäßig werden die Build -Skripte dort überall dort hingewiesen, wo das Python -Programm erwartet, dass installierte Python -Programme sein werden. Ein normaler Benutzer hat im Allgemeinen keinen Schreibzugriff auf dieses Verzeichnis.
Um dies zu überschreiben, können Sie die Optionen-mit Pythoninstall und-mit Pythoninstalllib-Konfiguration verwenden oder die Pythoninstalldir- und Pythoninstalllibdir-Umgebungsvariablen an der Stelle einstellen, an der die Bibliotheken und Module gehen sollen.
Beachten Sie, dass Sie möglicherweise festlegen müssen-mit UUCP-Sperren für Ihr Lockdir (auf älteren Systemen IT/var/Lock, das standardmäßig ist. Auf neuerer Weise können es/rennen/lock/lockDev sein. Möglicherweise müssen Sie auch sein Ein Mitglied von Dialout- und Sperrgruppen, um Seriengeräte und/oder Schlösser öffnen zu können.
GO -Sprachunterstützung erfordert, dass sie auf dem Weg installiert werden muss.
Als ich Gensios weiter in der Bibliothek hinzufügte, wie Crypto, MDNs, Sound, IPMI, SCTP usw. Die Anzahl der Abhängigkeiten in der Bibliothek geriet außer Kontrolle. Warum sollten Sie Libasound oder Libopenipmi laden, wenn Sie es nicht brauchen? Obwohl die Bibliothek das Hinzufügen Ihrer eigenen Gensios über eine programmatische API unterstützte, hatte sie keine Standardmethode, um sie für das System hinzuzufügen, damit Sie Ihren eigenen Gensio schreiben und alle auf dem System verwenden können.
Die Gensio -Bibliothek unterstützt das Laden von Gensios dynamisch oder baut sie in die Bibliothek auf. Wenn Sie standardmäßig gemeinsam genutzte Bibliotheken erstellen, werden alle Gensios als Module für dynamisches Laden zusammengestellt und an einem Ort installiert, der es ermöglicht. Wenn Sie keine gemeinsam genutzten Bibliotheken erstellen, sind alle Gensios in der Bibliothek eingebaut. Sie können dieses Verhalten jedoch überschreiben.
Um alle Genossios so einzustellen, dass sie in die Bibliothek eingebaut werden sollen, können Sie in der Befehlszeile Konfiguration "-mit allen Gensis = Ja" hinzufügen, und es wird sie in die Bibliothek erstellt.
Sie können sie auch so einstellen, dass alle dynamisch geladen werden, indem Sie "-mit all-gensios = dynamic" hinzufügen, aber dies ist die Standardeinstellung.
Sie können auch standardmäßig alle Gensios deaktivieren, indem Sie "-mit all-gensios = no" angeben. Dann werden standardmäßig kein Gensios erstellt. Dies ist nützlich, wenn Sie nur ein paar Gensios möchten. Sie können sie alle ausschalten und dann diejenigen, die Sie möchten.
Um festzustellen, wie einzelne Gensios erstellt werden, "-mit <fensio> = x" wobei x ist "Nein (nicht erstellen), Ja (in Bibliothek erstellen) oder dynamisch (dynamisch geladene ausführbare Datei). Zum Beispiel. Wenn Sie das TCP-Gensio nur in die Bibliothek aufbauen und den Rest dynamisch machen möchten, können Sie für alle dynamischen Gensios einrichten und dann "mit net = yes" hinzufügen.
Diese Module werden standardmäßig eingefügt
Beachten Sie, dass dynamisches Laden immer verfügbar ist, auch wenn Sie alle Gensios in der Bibliothek aufbauen. Sie können also weiterhin Ihre eigenen Gensios hinzufügen, indem Sie dann zum richtigen Verzeichnis hinzufügen.
Gensios werden zuerst aus der Umgebungsvariablen ld_library_path, dann von Gensio_Library_Path und dann vom Standardort geladen.
MacOS, die eine Art * Nix ist, baut ziemlich sauber mit Homebrew (https://brew.sh) auf. Sie müssen natürlich alle Bibliotheken installieren, die Sie benötigen. Fast alles funktioniert mit den folgenden Ausnahmen:
* CM108GPIO * sctp * UUCP -Verriegelung
Der integrierte DNSSD-Code wird für MDNs verwendet, sodass Avahi nicht erforderlich ist.
Herdenverriegelung für serielle Ports funktioniert, sodass UUCP -Sperren wirklich nicht erforderlich sind.
OpenIPMI sollte funktionieren, aber es ist nicht im Homebrew verfügbar, sodass Sie es selbst bauen müssen.
Installieren Sie die erforderliche Software:
- PKG Installation GCC Portaudio AutoConf Automake libtool mdnsresponder Swig
- Gehen Sie Python3 Gmake
Sie müssen Gmake verwenden, um es zu kompilieren. Aus irgendeinem Grund akzeptiert der Standard für BSD die Variable "C ++" in einer Liste von Anforderungen nicht. Die folgenden Funktionen funktionieren nicht und werden nicht zusammengestellt:
* sctp * ipmisol * CM108GPIO
Fügen Sie Folgendes zu /etc/rc.conf hinzu:
mdnsd_enable = ja
Und starten Sie den Service neu oder starten Sie den Dienst.
Der Pty Gensio scheitert den OomTest (OomTest 14), es scheint etwas mit den BSD -Ptys zu tun zu haben. Ich sehe in Fällen ein 07 -Zeichen, das in den Datenstrom eingefügt wurde. Ich habe jedoch nicht zu viel Zeit damit verbracht, aber da dies stark unter Linux und MacOS getestet wird, denke ich nicht, dass das Problem im Gensio -Code liegt.
Die Gensio -Bibliothek kann unter Windows mit Mingw64 erstellt werden. Die folgenden Dinge funktionieren nicht:
* sctp * Pam * libwrap * ipmisol
Sie müssen auch keine ALSA installieren, sondern die Windows -Sound -Schnittstelle für Sound.
Der CM108GPIO verwendet native Windows -Schnittstellen, sodass Udev nicht erforderlich ist.
Die Windows-integrierten MDNS-Schnittstellen werden verwendet, sodass Sie keine Avahi oder DNSSD benötigen. Sie müssen die PCRE -Bibliothek installieren, wenn Sie regelmäßige Ausdrücke darin möchten.
Sie müssen MSYS2 von https://msys2.org erhalten. Installieren Sie dann Autoconf, Automake, Libtool, Git, Make und Swig als Host -Tools:
Pacman -S Autoconf Automake Libtool Git machen Swig
Sie müssen die Mingw-W64-X86_64-XXX-Version aller Bibliotheken oder die Mingw-W64-I686-XXX-Version aller Bibliotheken installieren. 32-Bit ist nicht gut getestet:
Pacman -S Mingw-w64-X86_64-GCC mingw-w64-x86_64-python3 mingw-w64-x86_64-pcre Mingw-w64-X86_64-OpenSSL
für Mingw64 oder für UCRT64:
pacman -s mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-python3 mingw-w64-ucrt-x86_64-pcre Mingw-w64-uCRT-X86_64-OpenSSL
Für Go, installieren Sie sich von https://go.dev und melden Sie sich an und melden Sie sich wieder an. Es sollte dann im Pfad sein, aber wenn dies nicht der Fall ist, müssen Sie es dem Pfad hinzufügen. Ich habe nicht an Mingw32 gearbeitet, aber ich habe keine 32-Bit-Version von Go ausprobiert.
Für GTLSSHD hat -Sysconfdir unter Windows keine Bedeutung. Stattdessen ist das Sysconf -Dire relativ zum Patch der ausführbaren Datei in ../ETC/gtlsssh. Also, wenn GTLSSHD in:
C:/Programmdateien/Gensio/bin/gtlsshd
Das Sysconfdir wird:
C:/Programmdateien/Gensio/etc/gtlsssh
Für die Standardinstallation können Sie ausführen:
. ---mandir =/Gensio/Man---includedir =/Gensio/include -mit Pythoninstall =/Gensio/Python3--Prefix =/Gensio
Und wenn Sie "Installieren Sie destdir = ..." aus und setzen Sie das Ziel so, wo Sie es wollen, wie "c:/Programmdateien". Dann können Sie das mit dem Bedienfeld dem Pfad hinzufügen. Um GTLSSHD zu verwenden, erstellen Sie ein ETC/GTLSSHD -Verzeichnis im Gensio -Verzeichnis. Sie müssen die Berechtigungen in diesem Verzeichnis festlegen, damit nur Systeme und Administratoren Zugriff haben, z. B.:
PS C: Programmdateien (x86) Gensio etc> icacls gtlsssh GTLSSH NT Authority System: (OI) (CI) (F) BAUNE Administratoren: (OI) (CI) (f)
Andernfalls fehlschlägt GTLSSHD mit einem Fehler über die Berechtigungen des Schlüssels. Sie können diese Berechtigung in der Datei .Key anstelle des Verzeichnisses festlegen, müssen sie jedoch jedes Mal erneut festlegen, wenn Sie einen neuen Schlüssel generieren.
Um den Inno Setup -Compiler zu verwenden, machen Sie "Destdir = $ home/installieren Sie" und führen Sie dann Inno auf Gensio.ISS aus. Es wird ein ausführbares Installationsprogramm zur Installation von Gensio erstellt.
Anschließend müssen Sie die .la -Dateien aus dem Installationsverzeichnis entfernen, während sie die Verknüpfung mit anderen Dingen vermasseln:
rm $ home/install/Gensio/lib/*. la
Es gibt eine Reihe von Tests für Gensios. Sie alle laufen unter Linux, wenn Sie das Serialsim -Kernel -Modul haben. Neben den seriellen Ports laufen sie auf anderen Plattformen, da die Gensios auf dieser Plattform unterstützt werden.
Die seriellen Porttests erfordern das serielle Kernelmodul und die Python -Schnittstelle. Diese finden Sie unter https://github.com/cminyard/serialsim und ermöglichen es den Tests, einen simulierten seriellen Port zu verwenden, um die Modemsteuerung zu lesen, Fehler injizieren usw.
Sie können ohne serialsim auskommen, wenn Sie drei serielle Geräte haben: einen im Echo -Modus (RX und TX zusammengebunden) und zwei miteinander verbundene serielle Geräte. Dies sollte auf Nicht-Linux-Plattformen funktionieren. Stellen Sie dann die folgenden Umgebungsvariablen ein:
export GENSIO_TEST_PIPE_DEVS= " /dev/ttyxxx:/dev/ttywww "
export GENSIO_TEST_ECHO_DEV= " /dev/ttyzzz "
Es kann nicht in der Lage sein, Modemstate oder RS485 zu testen.
Sie benötigen außerdem das IPMI_SIM -Programm aus der OpenIPMI -Bibliothek unter https://github.com/cminyard/openipmi, um die IPMISOL -Tests auszuführen.
Um die Tests durchzuführen, müssen Sie einige interne Debuggen ermöglichen, um den vollen Effekt zu erzielen. Sie möchten im Allgemeinen so etwas führen wie:
./configure --enable-internal-trace CFLAGS= ' -g -Wall '
Sie können -O3 auch in den CFLAGs einschalten, wenn Sie möchten, aber es macht das Debuggen schwieriger.
Es gibt zwei grundlegende Arten von Tests. Die Python -Tests sind Funktionstests, die sowohl die Python -Schnittstelle als auch die Gensio -Bibliothek testen. Derzeit sind sie in Ordnung, aber es gibt viel Raum für Verbesserungen. Wenn Sie helfen möchten, können Sie Tests schreiben.
Der OomTest war früher ein aus Gedächtnisentester, hat sich aber in etwas Umfangreichere verwandelt. Es erzeugt ein Geniot -Programm mit bestimmten Umgebungsvariablen, damit es an bestimmten Stellen fehlschlägt und Speicherleck und andere Speicherprüfungen durchführt. Es schreibt Daten über sein Stdin an den Gensit und erhält Daten zu STDOut. Einige Tests (wie Serialdev) verwenden ein Echo. Andere Tests stellen eine separate Verbindung über das Netzwerk her, und die Daten fließen sowohl in stdin als auch in die separate Verbindung zurück und fließen in die separate Verbindung und kommen über STDOut zurück. OomTest ist multi-thread und die Anzahl der Threads kann gesteuert werden. OomTest hat viele Fehler gefunden. Es hat viele Knöpfe, aber Sie müssen sich den Quellcode für die Optionen ansehen. Es muss dokumentiert werden, wenn sich jemand freiwillig melden möchte ...
Um für Fuzzing einzurichten, installieren Sie AFL und konfigurieren Sie dann mit Folgendem:
mkdir Zfuzz ; cd Zfuzz
../configure --enable-internal-trace=yes --disable-shared --with-go=no
CC=afl-gcc CXX=afl-g++
Oder verwenden Sie Clang, falls verfügbar:
../configure --enable-internal-trace=yes --disable-shared --with-go=no
CC=afl-clang-fast CXX=afl-clang-fast++ LIBS= ' -lstdc++ '
Ich bin mir nicht sicher, warum die Libs -Sache oben notwendig sind, aber ich musste es hinzufügen, um es zu kompilieren.
Dann bauen. Dann "CD -Tests" und run "machen test_fuzz_xxx" wobei XXX einer von: certAuth, mux, ssl, telnet oder relpkt ist. Sie müssen wahrscheinlich einige Dinge anpassen, wird AFL Ihnen sagen. Beachten Sie, dass es für immer läuft, Sie müssen es, wenn Sie fertig sind.
Das Makefile in Tests/Makefile.am enthält Anweisungen zum Umgang mit einem Nicht -Reproduzieren für das Debuggen.
Das Ausführen der Codeabdeckung in der Bibliothek ist ziemlich einfach. Zuerst müssen Sie den Code konfigurieren, um die Abdeckung zu aktivieren:
mkdir Ocov ; cd Ocov
../configure --enable-internal-trace=yes
CC= ' gcc -fprofile-arcs -ftest-coverage '
CXX= ' g++ -fprofile-arcs -ftest-coverage '
Der Kompilieren und Lauf "make check".
Um den Bericht zu generieren, rennen Sie:
gcovr -f ' .*/.libs/.* ' -e ' .*python.* '
Dies erzeugt eine Zusammenfassung. Wenn Sie die Berichterstattung einzelner Zeilen in einer Datei sehen möchten, können Sie:
cd lib
gcov -o .libs/ * .o
Sie können in den einzelnen .gcov -Dateien nach Informationen über das, was abgedeckt wird, nachsehen. Weitere Details finden Sie in den GCOV -Dokumenten.
Zum Zeitpunkt des Schreibens erhielt ich ungefähr 74% Code -Berichterstattung, das ist also wirklich ziemlich gut. Ich werde daran arbeiten, dies zu verbessern, hauptsächlich durch verbesserte Funktionstests.
Ser2NET wird zum Testen einiger Dinge verwendet, vor allem die serielle Portkonfiguration (Termios und RFC2217). Sie können Ser2NET gegen die GCOV -Version der Gensio -Bibliothek erstellen und "Make Check" in Ser2NET ausführen, um diese Teile abzudecken. Damit sehe ich eine Abdeckung von etwa 76%, sodass es nicht viel zur Gesamtsumme erhöht.
Es wäre schön, dies mit Fuzzing kombinieren zu können, aber ich bin mir nicht sicher, wie das geht. AFL macht It It It Own Ding mit Code -Abdeckung. Es scheint ein AFL-COV-Paket zu geben, das GCOV irgendwie integriert hat, aber ich habe es nicht mitgeteilt.