<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">\documentclass[onecolumn,letterpaper,11pt]{article}

%===================================================================
\input{common_latex/common_latex_packages}
\input{common_latex/common_latex_definitions}
\input{common_latex/common_latex_memo_format}
%===================================================================

\begin{document}

\begin{labcover}
\labtitle{The Sock Ninja Utility Class for Socket Apps}
\vspace{0.17in}
\labpng{0.65}{figures/sock_ninja_ocean.png}
\vspace{0.15in}
\labdate{March 2020}
\vspace{0.1in}
\labauth{Michael Benjamin, mikerb@mit.edu}
\labauth{Department of Mechanical Engineering}
\labauth{MIT, Cambridge MA 02139}
\labtoc{small}
\end{labcover}

\wikidoc{file=Memo.SockNinja}
\wikidoc{auth=mikerb@mit.edu}


%====================================================================
\section{Overview}
%====================================================================

The SockNinja is a C++ utility class for facilitating (a) socket
configuration managment and (b) buffered communications I/O to and
from a configured socket.  As the number of apps grows, with a similar
need for socket comms, the goal of this class is to ease app
development. The idea is conveyed in Figure \ref{fig_app_ninja} below,
where each app contains an instance of the SockNinja to handle the
work of comms over a socket.

\vspace{0.1in}
\begin{figure}[ht]
  \centering 
  \includegraphics[width=0.4\textwidth]{figures/apps_ninja.png}
  \caption{{\bf The SockNinja Utility}: Applications needing to
    interface over a socket can use the SockNinja to facilitate
    socket configuration and I/O over the connected socket.}
\label{fig_app_ninja}
\end{figure}

\noindent
The SockNinja can be configured as either a client or server with
a single configuration parameter, and the SockNinja Read/Write interface
is the same in either client or server mode. This allows apps that
use the SockNinja to also be easily configurable to act in a client
or server mode. 

\vspace{0.1in}
\noindent
This document describes the basic usage of the SockNinja targeting the
application developer who may use this utility in their app.


%====================================================================
\subsection{Loose Relationship to MOOS-IvP}

Although the SockNinja is used in MOOS apps, the SockNinja code has no
dependency on MOOS, and may be used in any C++ application working
with a socket. There are some string parsing utlities from the IvP
codebase (from the \var{mbutils} library) used in the SockNinja. If a
user wished to use the SockNinja outside the IvP context, a few
utilities would need to be replaced. These functions will be listed later
in the document.

%====================================================================
\subsection{Loose Relationship to NMEA}




%====================================================================
\section{Using the Sock Ninja - A Simple Example}
%====================================================================

A simple example is given below to demonstrate a simple use case of
the SockNinja. This program may be invoked from the command line in
either the client or server mode. It will loop until connected and
then simply send a single message, looking for an incoming message, and
then exit.

\small
\begin{fileverb}
 1  #include &lt;iostream&gt;
 2  #include "MBUtils.h"
 3  #include "SockNinja.h"
 4  
 5  using namespace std;
 6  int main(int argc, char *argv[])
 7  {
 8    if(argc != 3)
 9      return(1);
10    string ninja_type = argv[1];
11    string user_greet = argv[2];
12  
13    SockNinja ninja(ninja_type, 29500);
14    ninja.setMsgFormatVerbatim(); 
15    while(!ninja.isConnected()) {
16      millipause(500);
17      cout &lt;&lt; "Waiting to connect..." &lt;&lt; endl;
18      ninja.setupConnection();
19    }
20  
21    ninja.sendSockMessage(user_greet);
22    cout &lt;&lt; "Reply:" &lt;&lt; ninja.getSockMessage() &lt;&lt; endl;
23  }  
\end{fileverb}
\normalsize

\vspace{0.1in}
\noindent
This program is compiled into the executable called
\app{testninja}. It takes two arguments. The first is either
\var{"client"} or \var{"server"}. The second argument is a message to
send.  To demonstrate, two instances are run, one as server and one as
a client, each with a different message.  Two terminals are needed. In
the first terminal, launch with the \var{server} option chosen, and a
simple message like \var{Hello}:

\vspace{0.15in}
\begin{consoleverb}
$ testninja server Hello
Waiting to connect...
Waiting to connect...
Waiting to connect...
Waiting to connect...
Waiting to connect...
\end{consoleverb}

\begin{consoleverb}
Waiting to connect...
Reply:Bonjour              (after the second testninja is later launched)
\end{consoleverb}

\vspace{0.1in}
\noindent
The first terminal will run indefinitely until a client connects. The next
step is to use a second terminal to launch a client version of \app{testninja},
providing another simple test message:

\begin{consoleverb}
$ testninja client Bonjour
Waiting to connect...
Reply:Hello
\end{consoleverb}

\vspace{0.1in}
\noindent
The second launching of \app{testninja} completes almost immediately. It
connects to the first version of the \app{testninja} allowing it to exit
the while-loop in lines 15-19. After each has connected to one another,
the greeting message is sent out, on line 21. The final step is to read
the incoming message from the other and write to the terminal, on line 22.

%====================================================================
\subsection{SockNinja Message Format Options}

In the example above, on line 14, the SockNinja is configured to send
and receive messages in the {\em verbatim} format. There is no expectation
of syntax, except newline characters are regarded as message separators.
The string \var{"Hello\textbackslash{n}{World}} would be regarded as two
messages. The default message format mode is \var{"nmea"}, in which
case incoming and outgoing messages are checked for proper NMEA syntax (but
not semantics), as part of the read or written functions. Improperly
formatted NMEA strings will be dropped but noted. More on NMEA format in
Section \ref{sec_msg_mode}

%====================================================================
\subsection{Sending Messages}

Messages are sent with the \var{sendSockMessage(string)} function. One
message per function call. A Boolean is returned, \var{true} if the
message is sent, and \var{false} if the socket is unable to send the
message or if the message is not a proper NMEA string if the message
format mode is configured to be \var{"nmea"}

%====================================================================
\subsection{Receiving Messages}

Messages are received with one of the two functions:

\begin{fileverb}
list&lt;string&gt; getSockMessages();
string getSockMessages();
\end{fileverb}

\vspace{0.1in}
\noindent
In both cases, the SockNinja will read data from the socket and fill
a list of received messages. The first function above retrieves all
received messages. The second function only retrieves the most recent
message. Both functions also clear the SockNinja's cache of received
messages as part of the function call.

%====================================================================
\subsection{Imagining the SockNinja in a MOOS App}

Note this simple program and the SockNinja have no dependency or
relationship to MOOS, but it's easy to see how this can and will be
used in MOOS apps.

\begin{packed_itemize}
\item The SockNinja is a member variable of the MOOS app, with the
  client/server mode, port number and IP address, all configurable
  from the \var{.moos} file.

\item In the \var{Iterate()} method, the SockNinja is repeatedly
  allowed to try to connect, until finally it succeeds.

\item The MOOS app may register for mail to send out with the
  SockNinja over the open socket.

\item The MOOS app may receive messages over the socket and publish
  the messages as mail notifications to the local MOOSDB.
\end{packed_itemize}


%====================================================================
\section{Configuring the Sock Ninja}
%====================================================================

The SockNinja has four primary configuration parameters: the client/server
mode, the port number, the IP address, and the message handling mode.

%====================================================================
\subsection{Configuring the Client or Server Mode, and Port Number}

The SockNinja can be configured as either a client or server, and this
is declared at the time of construction through a constructor parameter.

\begin{fileverb}
SockNinja ninja("server");    // Configured as server
or 
SockNinja ninja("client");    // Configured as client
or 
SockNinja ninja();            // Configured as server
or 
SockNinja ninja("blah");      // Configured as server
\end{fileverb}

\vspace{0.1in}
\noindent
The default type is server, if not specified in the constructor, or if the
argument is anything but \var{"client"}. The socket port number may be
set in the constructor, or after instantiation:

\begin{fileverb}
SockNinja ninja("client", 29500);   
or 
SockNinja ninja("client"); 
bool ok_port = ninja.setPortNumber(29500);
\end{fileverb}

\vspace{0.1in}
\noindent
The default port number is $29500$. The \var{setPortNumber(int)} function
will return \var{true} for any postitive integer, \var{false} otherwise.

%====================================================================
\subsection{Configuring the IP Address}

When the SockNinja is configured as a client, the IP address may be configured
to represent the address where the client should try to find the server. It
is configured with: 

\begin{fileverb}
SockNinja ninja("server");   
bool ok_port = ninja.setPortNumber(29500);
bool ok_addr = ninja.setIPAddress(12.34.56.78);
\end{fileverb}

\vspace{0.1in}
\noindent
The default IP address is \var{"localhost"}. The
\var{setIPAddress(string)} function will return \var{false} if: 

\begin{packed_itemize}
\item The SockNinja type is "server", or

\item The SockNinja client has already connected to a server, or

\item The IP address is not a valid IPv4 address.
\end{packed_itemize}

\vspace{0.1in}
\noindent
When the SockNinja is configured as {\em server}, the IP address cannot
be set. However, for a server, the IP address will represent
the address of the client when it connects to the server:

\begin{fileverb}
SockNinja ninja("server");   
...
string ip = ninja.getIPAddress();   // IP Addr of connected client, null if not connected
\end{fileverb}

\begin{fileverb}
SockNinja ninja("client");   
...
string ip = ninja.getIPAddress();   // IP Addr to look for server
\end{fileverb}


%====================================================================
\subsection{Configuring the Message Handling Mode}
\label{sec_msg_mode}

Message handling can be configured to operate in one of two modes. In
the {\em verbatim} mode, no message syntax is checked for, and
messages are separated by the newline ({\tt \textbackslash {n}})
character.

\vspace{0.1in}
\noindent
In the default, NMEA mode, incoming and outgoing messages are expected
to be valid NMEA strings. A valid NMEA string is of the form:

\begin{consoleverb}
$ABCDE,one,two,three,four,five*HH\r\n
\end{consoleverb}

\vspace{0.1in}
\noindent
The first character is a dollar-sign, followed by a five character
header, followed by some number of comma-separated fields, terminated
by an asterisk.  The first two characters after the asterisk are a
two-digit hex checksum of the first part of the message in between the
dollar sign and asterisk. The NMEA message is terminated by CRLF,
carriage-return and line-feed characters, ASCII values 13 and 10
respectively.

\vspace{0.1in}
\noindent
In the NMEA mode, the SockNinja will reject messages passed to
\var{sendSockMessage(string)} if the string argument is not a valid
NMEA message.  Incoming messages read from the socket will also be
checked for NMEA compliance or else rejected. More will be said about
reading from the socket later in section \ref{sec_sock_read}. The {\em
  semantics} of the message, e.g., the comma-separated content, are
not checked for by the SockNinja. Semantics are application/user
specfic and endless in variety. The SockNinja is intended to be
application agnostic.

%====================================================================
\section{Internally Generated Status Messages}
%====================================================================

As the SockNinja is used, during configuration, connection and
operation, it may generate event or warning messages as simple
strings. The SockNinja maintains a list for each, finite in length,
eventually dropping older messages for newer messages.  The user of
SockNinja has the option of retrieving these messages to use in
whatever manner is appropriate for the application. There is no harm
in {\em not} retrieving them, as the internal lists are bounded in
size/memory.  In the case of a MOOS app using a SockNinja, the
messages are posted to the AppCast/terminal output, as discussed in 
Section \ref{sec_msg_acast}.

%====================================================================
\subsection{Types of Status Messages: Events, Warnings, and Retractions}

There are three types of messages:

\vspace{0.1in}
\noindent
\begin{packed_itemize}
\item {\em Event} messages typically indicate changes of status, or
  things that should not be raised to the level of a warning. For
  example the successful connection to a socket.
 
\item {\em Warning} messages are events that are intended to be brought
  to the attention of a user. For example a disconnected socket.

\item {\em Retraction} messages are events that indicate a warning has
  been resolved. For example a reconnected socket, previously disconnected.
\end{packed_itemize}

\vspace{0.1in}
\noindent
An example event:

\begin{consoleverb}
Listening for connection on port 29500
\end{consoleverb}

\vspace{0.1in}
\noindent
An example warning:

\begin{consoleverb}
Disconnected
\end{consoleverb}

\vspace{0.1in}
\noindent
An example retraction:

\begin{consoleverb}
Disconnected
\end{consoleverb}

\vspace{0.1in}
\noindent
Retractions are strings designed to "match" a previous warning with an
identical string value. This convention also happens to be consistent with
how AppCasting apps handle warnings and retractions.

%====================================================================
\subsection{Retrieving the Status Messages}

The SockNinja implements three methods for retrieving status messages:

\begin{fileverb}
list&lt;string&gt; getEvents();
list&lt;string&gt; getWarnings();
list&lt;string&gt; getRetractions();
\end{fileverb}

\vspace{0.1in}
\noindent
In all three methods, the internal SockNinja list of status messages
is cleared as a side effect of the function call. Presumably these
functions are called on a regular basis. In MOOS apps they likely
would be called in the \var{Iterate()} loop.


%====================================================================
\subsection{Using the Status Messages in a Vanilla C++ App}

For a vanilla C++ app, the below is an example how this information may
be retrieved and used:

\vspace{0.1in}
\begin{fileverb}
SockNinja ninja("client");
. . .
list&lt;string&gt;::iterator p;
list&lt;string&gt; events = ninja.getEvents();
list&lt;string&gt; warnings = ninja.getWarnings();
list&lt;string&gt; retractions = ninja.getRetractions();

cout &lt;&lt; "Events: " &lt;&lt; endl;
for(p=events.begin(); p!=events.end(); p++)
  cout &lt;&lt; "  " &lt;&lt; *p &lt;&lt; endl;

cout &lt;&lt; "Warnings: " &lt;&lt; endl;
for(p=warnings.begin(); p!=warnings.end(); p++)
  cout &lt;&lt; "  " &lt;&lt; *p &lt;&lt; endl;

cout &lt;&lt; "Retractions: " &lt;&lt; endl;
for(p=retractions.begin(); p!=retractions.end(); p++)
  cout &lt;&lt; "  " &lt;&lt; *p &lt;&lt; endl;
\end{fileverb}


%====================================================================
\subsection{Using the Status Messages in an AppCasting MOOS App}
\label{sec_msg_acast}

In a MOOS app, the events, warnings, and retractions line up nicely
with the features of AppCasting. The below snippet of code would likely
be found at the end of the \var{Iterate()} loop:

\small
\begin{fileverb}
// m_ninja is a SockNinja member variable of the MOOS App

list&lt;string&gt;::iterator p;
list&lt;string&gt; events      = m_ninja.getEvents();
list&lt;string&gt; warnings    = m_ninja.getWarnings();
list&lt;string&gt; retractions = m_ninja.getRetractions();

for(p=events.begin(); p!=events.end(); p++)
  reportEvent(*p);
for(p=warnings.begin(); p!=warnings.end(); p++)
  reportWarning(*p);
for(p=retractions.begin(); p!=retractions.end(); p++)
  reportRetraction(*p);
\end{fileverb}
\normalsize

\vspace{0.1in}
\noindent
The \var{reportEvent()}, \var{reportWarning()}, and
\var{reportRetraction()} methods are AppCastingMOOSApp methods that ensure
this information is updated to the next-generated AppCast.

%====================================================================
\section{Obtaining Sock Ninja Config State and Statistics}
%====================================================================
\label{sec_ninja_stats}

The SockNinja supports an interface for obtaining the (a) the current
state of configuration and connection, and (b) the total messages
sent and received, along with the most recent of each. 

%====================================================================
\subsection{Obtaining SockNinja Config and Connection State}

The SockNinja config and connection state is comprised of the following
pieces of information:

\begin{packed_itemize}
\item {\em Ninja Type}: A string, either "server" or "Client"
\item {\em Format}: A string, either "verbatim" or "nmea" 
\item {\em IP address}: A string holding a IPv4 formatted addres,
  e.g., 12.34.56.78
\item {\em Port number}: An integer value, e.g., 29500
\item {\em State}: A string, either "unconnected", "listening", or "connected".
\end{packed_itemize}

\vspace{0.1in}
\noindent
The coresponding SockNinja functions are:

\begin{fileverb}
string SockNinja::getType();
string SockNinja::getFormat();
string SockNinja::getIPAddr();
string SockNinja::getState();
int    SockNinja::getPort();
bool   SockNinja::isConnected();  // convenience function
\end{fileverb}

\vspace{0.1in}
\noindent
A further pair of convenience functions are provided for getting all
five values. Information can be obtained in either a verbose or terse
format. The terse format will return a single string. 

\begin{fileverb}
  list&lt;string&gt; SockNinja::getSummaryStatComms(bool terse=false);
\end{fileverb}

\vspace{0.1in}
\noindent
The non-terse mode will provide six strings:

\begin{consoleverb}
Status:
  Type:   server
  Format: nmea
  State:  connected
  Port:   29500
  IPAddr: 12.34.56.78 (client)
\end{consoleverb}

\vspace{0.1in}
\noindent
The terse mode will provide a single string:

\begin{consoleverb}
server/nmea/connected/29500/29500/12.34.56.78 (of client)
\end{consoleverb}

\vspace{0.1in}
\noindent
When the SockNinja is of type {\em server}, the IP address shown will be of
the connected client if it is connected. When it is of type {\em client}, the
IP address will be of the server to which is connected, or trying to connect
to.

%====================================================================
\subsection{Obtaining SockNinja Send/Receive Stats}

The SockNinja send/received stats are comprised of the following
pieces of information:

\begin{packed_itemize}
\item {\em Total Sent}: An unsigned int total for each message sent,
\item {\em Total Received}: An unsigned int total for each message received,
\item {\em Most Recent Sent}: A string containing the most recent message
  successfully sent.
\item {\em Most Recent Received}: A string containing the most recent
  message successfully sent.
\end{packed_itemize}


\vspace{0.1in}
\noindent
When operating in the NMEA mode, the SockNinja also stores this
information {\em per message type}, keyed on the 5-digit NMEA header
string. The SockNinja functions for getting this info are below. When
a key is not provided, it will return the info related to all
messages. When a key is provided and found, it will return the
information related only to that key.

\begin{fileverb}
unsigned int SockNinja::getTotalMsgsSent(string key="");
unsigned int SockNinja::getTotalMsgsRcvd(string key="");
string SockNinja::getLastMsgSent(string key="");
string SockNinja::getLastMsgRcvd(string key="");
\end{fileverb}

\vspace{0.1in}
\noindent
A further convenience function is provided for getting a summary of
all incoming and outgoing messages, in the form of a list of strings
with one function call:

\begin{fileverb}
  list&lt;string&gt; SockNinja::getSummaryStatMsgs();
\end{fileverb}

\vspace{0.1in}
\noindent
This will provide a list of strings like the example below. The length
of the list depends on how many message types exist.

\begin{consoleverb}
NMEA sentences:            
&lt;--R      27  $PYDIR,45,55*57
 S--&gt;     27  $CPNVG,134213.686,0000.00,N,00000.00,W,1,,,0,,,134213.686*64
 S--&gt;     27  $CPRBS,134213.686,1,15.2,15.1,15.3,0*5B
 S--&gt;     27  $GPRMC,134213.686,A,0000.00,N,00000.00,W,0,0,291263,0,E*67
\end{consoleverb}

\vspace{0.1in}
\noindent
The first column indicates whether the message was sent or received. The
second column shows the number of messages for that message type, and the
remainder of the string shows the most recent message for that type.


\end{document}




</pre></body></html>