Section 1: Basic concepts to starting writing with or integrating noPoll:
Section 2: Advanced concepts to consider:
Section 3: using noPoll TLS API:
Section 4: Android platfom notes:
Currently, noPoll has only one dependency, which is OpenSSL (libssl) for all those crypto operations required by the protocol itself.
After having that library installed in your system (check your OS documentation), download lastest tar.gz noPoll library from: http://www.aspl.es/nopoll/downloads
Then, to compile the library follow the standard autoconf voodoo:
At this point, if everything went ok, you can check the library by running in one terminal:
And then in another terminal the client regression test:
Notes about preparing sources if you use SVN/GIT from https://github.com/asples/nopoll
In the case you want to work directly using SVN latest sources, just download them from githubt as usual from: https://github.com/asples/nopoll
After that, run the following command to prepare all compilation files:
If everything looks fine, you can install nopoll into your system with the standard:
After a successful noPoll installation, you should be able to include noPoll API functions by including the following header:
Then you can use the following to get nopoll compilation flags:
Or if your project uses autoconf for the building process, just include the following into your configure.ac file:
noPoll is designed as a thread agnostic stateless library so it can fit in any project configuration (no matter if it uses threads or event notification).
In the case you are planning to use noPoll in a project that uses threads and you expect to make calls to the noPoll API from different threads at the same time, then you must setup four callbacks that will help noPoll to create, destroy, lock and unlock mutexes. For that, check documentation about nopoll_thread_handlers
Before working with noPoll API you must create a noPollCtx object, which represents a single library instance state. You can create as much noPollCtx objects inside the process as you want. To create it you must do something like:
Now let's see how to create a simple WebSocket server using noPoll own loop:
Now, every time a frame is received, the handler listener_on_message will be called. Here is an example about that handler:
The process of creating a WebSocket connection is really simple. After creating a context (noPollCtx) you connect to the listener by using:
After that, you can call to nopoll_conn_is_ready to check if the connection is ready to send and receive content. If you don't have a loop to wait on, you can use the following function to wait for the connection to be ready:
In any case, once the connection is ready, either because nopoll_conn_is_ready returned nopoll_true or because you used nopoll_conn_wait_until_connection_ready, you can send a message by using the following:
Now, to receive the content from this connection see the following.
Now, to receive content from connections (or to handle master listeners requests) you can use the following methods:
Ok, in general it does, however we would have to look into the particular case to give a correct answer. That's because the term "fragment" is really broad especially for WebSocket.
In general, you shouldn't design in a way that this is important for your application to work. All about WebSocket must be designed as if you were working with a stream oriented socket.
For example, WebSocket standard states that any intermediary may split or join frames. And by any intermediary we mean any WebSocket stack in the middle of the transmission including the sender and the receiver.
The practical implication is that if your WebSocket peer sends a message, it may reach to the other peer consolidated along with other smaller messages or it may be received as several "complete" WebSocket frames.
In general noPoll tries to consolidate internal frame fragments but only for some particular functions like (nopoll_conn_get_msg). For example, if a frame fragment is received, that is, just the header and part of the body, this particular function will "wait" until the entire body is received. And by "wait" we mean the function will return NULL, waiting you to call again in the future to get the entire message.
In general, even though the standard allows it (as we saw), noPoll doesn't do any split or join operation to avoid confusion. However, some API calls like nopoll_conn_read, which provides an "stream view" of the connection, will serve bytes as they come (so the frame concept is not present in this case).
Every time you do a write operation (using for example nopoll_conn_send_text or nopoll_conn_send_text_fragment) there is a possibility that the write operation failes because the socket isn't capable to keep on accepting more data.
In that case, errno == 11 (or NOPOLL_EWOULDBLOCK) is returned so you can check this to later retry the write operation.
Because websocket involves sending headers that already includes the size of the message sent, you can't just retry by calling again to the send operation used (like nopoll_conn_send_text), especially because you must "continue" the send operation where it was left instead of sending more content with additional headers. In short, you must complete the operation.
To this end, you must use the following functions to check and complete pending write operations:
Here is a posible complete function considering all points:
As we can see, the example tries to first write the content and then check for errors, trying to complete write in the case of errno == NOPOLL_EWOULDBLOCK, but, before going ahead retrying, the function sleeps a bit.
A very important note to consider is that this isn't by far the best way to do this. This example is just to demonstrate the concept. The "ideal" implementation would be not to do any retry here (second part) but let the engine looping and waiting for this WebSocket to retry later, letting the overall application to keep on doing other things meanwhile (like writing or handling I/O in other connections) rather than locking the caller (as the example do).
Knowing this, if you want a ready to use function that implements concept (for the second part), you can directly use:
With it, a fairly complete and efficient write operation would be:
Current noPoll design allows to implement full WebSocket connection accept by calling to nopoll_conn_accept but also it is possible to let other application to do the accept connection, try to guess if what is comming is a WebSocket connection, to then let noPoll to complete the accept socket operation.
As a example, these concepts are being implemented by Vortex Library (http://www.aspl.es/vortex) to allow running on the same port BEEP and BEEP over WebSocket.
The way each application implements "port sharing concept" is really especific to each case, but here are the general steps:
In the case you want to verify provided client certificate at the server you can use the following code. It optionally provides the CA (as root.pem) which will make the listener to also verify client matches that CA. However, if you remove that CA (root.pem) your server will just verify peer's certificate:
Here the important part is calling to nopoll_conn_opts_ssl_peer_verify. This is because peer verification is disabled for servers (that is, servers by default do not verify peer's certificate which usually is not provided). However, this is not true for clients which is by default enabled (of course, client must always verify server's certificate when connecting with TLS/SSL, was we have said, this can be controlled by nopoll_conn_opts_ssl_peer_verify too).
Now, in the case you want to provide client certificate for a WebSocket connecting node, use the following:
The idea is to configure the following handler at your server/listener component:
Now, somewhere, that handler will have the following signature and code example:
For example, to get the certificate that is proposing the client you could use:
In the case you want to create the SSL_CTX/SSL object so it uses certain configurations like chain certificates, etc, so that the verification will only work when matching these settings.
If this is the case you'll have to use a different handler that will help noPoll engine to create the SSL context with the settings you want. By default, the SSL context is created with default settings if no handler is provided.
In the case you want to provide a ssl context creator, use:
And your handler will have the following signature with a very basic configuration:
As you can see, the function must return an SSL_CTX for every connection received and attempting to start TLS session.