@node Sockets APIs
@chapter Sockets APIs
The @uref{http://en.wikipedia.org/wiki/Berkeley_sockets,,sockets API}
is a long-standing API used by user-space applications to access
network services in the kernel. A ``socket'' is an abstraction, like
a Unix file handle, that allows applications to connect to other
Internet hosts and exchange reliable byte streams and unreliable
datagrams, among other services.
ns-3 provides two types of sockets APIs, and it is important to
understand the differences between them. The first is a @emph{native}
ns-3 API, while the second uses the services of the native API to
provide a @uref{http://en.wikipedia.org/wiki/POSIX,,POSIX-like}
API as part of an overall application process. Both APIs strive
to be close to the typical sockets API that application writers
on Unix systems are accustomed to, but the POSIX variant is much
closer to a real system's sockets API.
@section ns-3 sockets API
The native sockets API for ns-3 provides an interface to various
types of transport protocols (TCP, UDP) as well as to packet sockets
and, in the future, Netlink-like sockets. However, users are cautioned
to understand that the semantics are @strong{not} the exact same as
one finds in a real system (for an API which is very much aligned
to real systems, see the next section).
@code{class ns3::Socket} is defined in @code{src/node/socket.cc,h}.
Readers will note that many public member functions are aligned
with real sockets function calls, and all other things being equal,
we have tried to align with a Posix sockets API. However, note that:
@itemize @bullet
@item ns-3 applications handle a smart pointer to a Socket object, not
a file descriptor;
@item there is no notion of synchronous API or a ``blocking'' API;
in fact, the model for interaction between application and socket is
one of asynchronous I/O, which is not typically found in real systems
(more on this below);
@item the C-style socket address structures are not used;
@item the API is not a complete sockets API, such as supporting
all socket options or all function variants;
@item many calls use @code{ns3::Packet} class to transfer data
between application and socket. This may seem a little funny to
people to pass ``Packets'' across a stream socket API, but think
of these packets as just fancy byte buffers at this level (more
on this also below).
@end itemize
@subsection Basic operation and calls
@float Figure,fig:sockets-overview
@caption{Implementation overview of native sockets API}
@image{figures/sockets-overview, 10cm}
@end float
@subsubsection Creating sockets
An application that wants to use sockets must first create one.
On real systems, this is accomplished by calling socket():
@verbatim
int
socket(int domain, int type, int protocol);
@end verbatim
which creates a socket in the system and returns an integer descriptor.
In ns-3, we have no equivalent of a system call at the lower layers,
so we adopt the following model. There are certain @emph{factory}
objects that can create sockets. Each factory is capable of creating
one type of socket, and if sockets of a particular type are able to
be created on a given node, then a factory that can create such sockets
must be aggregated to the Node.
@verbatim
static Ptr<Socket> CreateSocket (Ptr<Node> node, TypeId tid);
@end verbatim
Examples of TypeIds to pass to this method are @code{TcpSocketFactory},
@code{PacketSocketFactory}, and @code{UdpSocketFactory}.
This method returns a smart pointer to a Socket object. Here is an
example:
@verbatim
Ptr<Node> n0;
// Do some stuff to build up the Node's internet stack
Ptr<Socket> localSocket = Socket::CreateSocket (n0, TcpSocketFactory::GetTypeId ());
@end verbatim
In some ns-3 code, sockets will not be explicitly created by user's
main programs, if an ns-3 application does it. For instance, for
@code{class ns3::OnOffApplication}, the function @code{StartApplication()}
performs the socket creation, and the application holds the socket
pointer.
@subsubsection Using sockets
Below is a typical sequence of socket calls for a TCP client in a
real implementation:
@itemize @bullet
@item @code{sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);}
@item @code{bind(sock, ...);}
@item @code{connect(sock, ...);}
@item @code{send(sock, ...);}
@item @code{recv(sock, ...);}
@item @code{close(sock);}
@end itemize
There are analogs to all of these calls in ns-3, but we will focus on
two aspects here. First, most usage of sockets in real systems
requires a way to manage I/O between the application and kernel.
These models include @emph{blocking sockets}, @emph{signal-based I/O},
and @emph{non-blocking sockets} with polling. In ns-3, we make use
of the callback mechanisms to support a fourth mode, which is
analogous to POSIX @emph{asynchronous I/O}.
In this model, on the sending side, if the @code{send()} call were to
fail because of insufficient buffers, the application suspends the
sending of more data until a function registered at the
@code{SetSendCallback()} callback is invoked. An application can
also ask the socket how much space is available by calling
@code{GetTxAvailable ()}. A typical sequence of events for
sending data (ignoring connection setup) might be:
@itemize @bullet
@item @code{SetSendCallback (MakeCallback(&HandleSendCallback));}
@item @code{Send ();}
@item @code{Send ();}
@item ...
@item @code{// Send fails because buffer is full}
@item (wait until HandleSendCallback() is called)
@item (HandleSendCallback() is called by socket, since space now available)
@item @code{Send (); // Start sending again}
@end itemize
Similarly, on the receive side, the socket user does not block on
a call to @code{recv()}. Instead, the application sets a callback
with @code{SetRecvCallback ()} in which the socket will notify the
application when (and how much) there is data to be read, and
the application then calls @code{Recv()} to read the data until
no more can be read.
@subsection Packet vs. buffer variants
There are two basic variants of @code{Send()} and @code{Recv()} supported:
@verbatim
virtual int Send (Ptr<Packet> p) = 0;
int Send (const uint8_t* buf, uint32_t size);
Ptr<Packet> Recv (void);
int Recv (uint8_t* buf, uint32_t size);
@end verbatim
The non-Packet variants are left for legacy API reasons. When calling
the raw buffer variant of @code{Send()}, the buffer is immediately
written into a Packet and the @code{Send (Ptr<Packet> p)} is invoked.
Users may find it semantically odd to pass a Packet to a stream socket
such as TCP. However, do not let the name bother you; think of
@code{ns3::Packet} to be a fancy byte buffer. There are a few reasons why
the Packet variants are more likely to be preferred in ns-3:
@itemize @bullet
@item Users can use the Tags facility of packets to, for example, encode
a flow ID or other helper data.
@item Users can exploit the copy-on-write implementation to avoid
memory copies (on the receive side, the conversion back to a
@code{uint8_t* buf} may sometimes incur an additional copy).
@item Use of Packet is more aligned with the rest of the ns-3 API
@end itemize
@subsection Sending dummy data
Sometimes, users want the simulator to just pretend that there is an
actual data payload in the packet (e.g. to calculate transmission delay)
but do not want to actually produce or consume the data. This is
straightforward to support in ns-3; have applications call
@code{Create<Packet> (size);} instead of @code{Create<Packet> (buffer, size);}.
Similarly, passing in a zero to the pointer argument in the raw buffer
variants has the same effect. Note that, if some subsequent code tries
to read the Packet data buffer, the fake buffer will be converted to
a real (zero'ed) buffer on the spot, and the efficiency will be lost there.
@subsection Socket options
@emph{to be completed}
@subsection Socket errno
@emph{to be completed}
@subsection Example programs
@emph{to be completed}
@section POSIX-like sockets API
@emph{this capability is under development and is scheduled for
inclusion in August 2008 timeframe; see the repository
http://code.nsnam.org/mathieu/ns-3-simu for details}
The below is excerpted from Mathieu's post to ns-developers list
on April 4, 2008.
"To summarize, the goal is that the full posix/socket API is defined in
src/process/simu.h: each posix type and function is re-defined there
with a simu_ or SIMU_ prefix to avoid ugly name clashes and collisions
(feel free to come up with a better prefix).
Each process is created with a call to ProcessManager::Create and is
attached to that ProcessManager instance. So, if the ProcessManager
(which is aggregated to a Node in src/helper/process-helper.cc) is
killed when the simulation ends, the system will automatically reclaim
all the resources of each process associated to each manager. The same
happens when an application "exits" from its main function.
The example application defines two posix "processes": the function
ClientProgram creates a udp socket on the localhost port 2000 and the
function ServerProgram creates a udp socket on the localhost port 2000.
The code does not work right now because I did not get the details of
simu_read right yet but, I do plan to make this work at some point.
I really think that this approach is worthwhile for many reasons, a few
of which are outlined below:
@itemize @bullet
@item makes porting real world application code _much_ easier
@item makes write applications for new users much easier because they can
read the bsd socket api reference and documentation and write code
directly.
@item can be used to write applications which work in both simulation and
in the real world at the same time. To do this, all you have to do is
write your application to use the simu_ API, and, then, you can chose at
compile-time which implementation of that API you want to use: you can
pick one implementation which forwards all calls to the system BSD
socket API or another one which forwards all calls to the attached
ProcessManager. Arguably, I did not implement the version which forwards
to system BSD sockets but, that should be pretty trivial.
@end itemize
So, anyway, comments about the overall API would be welcome. Students
interested in the gsoc project for real-world code integration should
consider looking at this also."