Over a million developers have joined DZone.

Mongoose Embedded Web Server: Internal Networking Interface

Get a look at how Mongoose's embedded web server has been reconstructed to support a wider array of devices while keeping its use simple.

· IoT Zone

Access the survey results 'State of Industrial Internet Application Development' to learn about latest challenges, trends and opportunities with Industrial IoT, brought to you in partnership with GE Digital.

All problems in computer science can be solved by another level of indirection, except of course for the problem of too many indirections. — David Wheeler

A great quote and a good intro to this blog post! We want to give you an insight into the Internal Networking Interface (INI) of the Mongoose Embedded Web Server.

The Background

Originally, Mongoose used a BSD-socket API and lot of socket functions and a non-blocking mode. That meant it was portable only to platforms that supported this API. It worked somewhat for those platforms supporting sockets. But we found that most platforms do support in their own way. Hardware SDK authors “forget” the select function. Also, they like to combine select and accept functions. This made our original BSD-socket API solution difficult to use. We had two options to fix it:

  1. Do not port to platforms that don’t simply support a full sockets API.
  2. Implement any missing functions for each platform.

Heroic Moves

Option one isn’t really the heroic way of doing things, right? We love complexity.

The first microchip Mongoose was ported to was Arduino (Mega). And it was implemented using the second way. We developed a BSD-socket layer on top of the Arduino Socket Library. It worked fine — though with some hiccups.

The next platform was ESP8266. Here, we had to decide what we really wanted to achieve. We started to work with ESP8266 a long time ago. There wasn’t an RTOS SDK with LWIP (and BSD sockets). Also, we wanted to port Mongoose to so many more embedded platforms and were beginning to understand that most of them would have problems with BSD sockets.

It was a time to split Mongoose Embedded Web Server into protocol level and network level. Yes, David Wheeler, time to add another level of indirection.

Planning Our Internal Networking Interface

Our Internal Networking Interface (INI) was supposed to:

  1. Be connection-(not socket!)-oriented. Mongoose is connection-oriented, so, the usage of a connection-oriented interface should be simpler.
  2. Support both TCP and UDP (the rest of supported protocols are based on these two).
  3. Be async, callback based.
  4. Be simple!

You’ve guessed it, the most problematic point was: Be simple. Our conundrum:

On the one hand, it is easy to design a hard-to-use interface, but then who is going to use it?

On the other hand, Mongoose has so many features, including network-related features, it was important to find a balance between functionality and simplicity.

As a result, the Mongoose Internal Networking Interface has ~20 functions.

Overview of the INI

There are several groups of functions in the INI API:

  1. Connections management.
  2. Data send and receive.
  3. Client functions.
  4. Server functions.
  5. A small set of utility functions.

Most functions (except the connections management functions) have two versions: one for TCP and one for UDP.

Last but not least, there is a set of callbacks. Our INI has a callback-based interface. In short, that means, that functions like connect return intermediately and invoke a callback. Then, a connection is established (or an error occurs).

The layer-interactions scheme is quite traditional: Application-level protocols use a transport protocols API while transport protocols use the INI implementations to communicate with the platform (or device) specific API.

Internet Netowrking Interface

At this moment, we have three implementations of the INI:

  1. BSD Sockets.
  2. LWIP.
  3. SimpleLink (Texas Instruments CC3100/C3200).

A specific implementation of the INI is selected at compile time by defining the CS_PLATFORM macros (these macros can be specified manually, using the compiler option, or a set of #ifdef #else in the Mongoose code will try to do it for you).

How it Works

The specific INI implementation must implement a set of functions to create connections, send data, receive it, etc. The core calls these functions to create the connections, send data, etc. If the INI wants to deliver any kind of information to the core, it invokes a callback implemented mostly in Mongoose Core rather than in the INI, i.e. the INI implementor should not provide the implementation of such functions (in most cases they name are ended with _cb). However, the INI should implement one callback as well (mg_if_recved, see below).

Here is small diagram of the execution sequence:

Mongoose Internal Networking Interface

Functions

Now, let’s do quick overview of the INI functions (a full description can be found in the Mongoose documentation here).

Connections Management Functions

Most of the activities related to connections management are performed by Mongoose itself, so the INI has functions to fulfill platform specific actions. For example, the “Socket INI” creates sockets in its implementation of mg_if_create_conn.

  • mg_if_create_conn.
  • mg_if_destroy_conn.
  • mg_close_conn.

Client and Server Functions

  • mg_if_connect_tcp.
  • mg_if_connect_udp.

Once a connection is established, the mg_if_connect_cb function should be invoked.

  • mg_if_listen_tcp.
  • mg_if_listen_udp.
  • mg_if_accept_new_conn.

Then the INI accepts the new connection and it should invoke mg_if_accept_tcp_cb.

Send and Receive Functions

  • mg_if_tcp_send, mg_if_udp_send and corresponding callback mg_if_sent_cb.

On receive, the INI should invoke the callbacks mg_if_recv_tcp_cb and mg_if_recv_udp_cb. If the core acknowledges consumption, it calls mg_if_recved.

Mission Accomplished?

Did we achieve what we set out to do? Here's a reminder of what we wanted:

Our Internal Networking Interfaces (INMI) was supposed to be:

  1. Be connections (not socket!) oriented - Mongoose is connection oriented, so, the usage of a connections oriented interface should be more simple.
  2. Support both TCP and UDP (the rest of supported protocols are based on these two).
  3. Be async, callback based.
  4. Be simple!

We think we got it. There is now a way to port Mongoose to different platforms. It may not always be super simple, but it is possible, and we don’t need to create shortcuts and things like that to make it happen.

A look into the future, we are planning to port Mongoose to even more embedded platforms. So we’ll end up with five-six different INI implementations. Stay tuned for it!

The IoT Zone is brought to you in partnership with GE Digital.  Discover how IoT developers are using Predix to disrupt traditional industrial development models.

Topics:
server ,networking ,ini ,implementation ,api ,embedded ,interface ,mongoose

Published at DZone with permission of Alexander Alashkin, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}