C Bindings – Python extensions

This is my third post on C extensions for other languages. I started with Lua, and my second post was about creating a C library for Java. This time I’m going to display how this works for Python.

Why would I want to do this? I already explained it in the previous posts, but to sum it up: You get all the advantages of C – Better performance, smaller footprint and direct access to platform resources. But with the cost of losing the platform independency that these higher-level languages (/scripts) have.

Python has an extensive documentation,and also specifically on its C API. You can find it all here.

As with the previous examples, I will export my “Unix Domain Sockets” client library to Python. And of course, the code for this post is available on github as well. The library I wrote is compatible with Python 2.7, instructions on how to port python C extensions from v2.7 to v3 (and above) are found here.

Building a dynamic library for Python

You don’t use a makefile in order to build your library (although it can be done, probably not recommended). Instead, you create a Python script named “setup.py” where you specify, using Python classes, the information you usually write in your makefile. For example – what are the source files, which libraries you use, libraries locations, etc.
You can also define a different compiler (the default is gcc), if your library is for a different platform then the build machine.

This is my setup.py:

from distutils.core import setup, Extension

UnixSockets = Extension('UnixSockets',
                        sources = ['src/python/unixsockets.c'],
                        library_dirs = ['unix_sockets/'],
                        libraries = ['client'],
                        include_dirs = ['unix_sockets/src/include/'])

setup(name = 'UnixSockets',
      version = '1.0',
      description = 'Unix sockets library for python',
      ext_modules = [UnixSockets])

As you can see, the parameters for “Extension” really do remind a makefile content. This class defines what will be compiled (and linked) and how. The “setup” class defines the build output.
This is just a simple example, more information on creating the setup script can be found here. And these are distutils.core API specifications.

Some other definitions go into setup.cfg, I used this file in order to define the build location. More information about this file – Here.

Using setup.py, building our extension becomes very easy:

python setup.py build

And installing it is not harder than that:

sudo python setup.py install

Implementation

Just exposing the C API (open/close/read/write) to Python is too easy, and lack any architectonic sophistication – So what’s the fun about that?
Instead, I wanted to create a new Python class, which opens a socket on creation, and closes it once it is disposed by the interpreter’s garbage collector.

Defining a new class

This is how our Python object looks like:

typedef struct {
    PyObject_HEAD
    int fd;
} socket;

All Python classes must “inherit” (a C-style inheritance) from PyObject, hence the _HEAD macro. But this is not the whole class, we need some more definition in order to make this a new Python type. I see this struct just as an object prototype.

This is how we define a new type in Python:

static PyTypeObject socketType = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "UnixSockets.Socket",      /*tp_name*/
    sizeof(socket),            /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)socketDealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    "Unix socket",             /* tp_doc */
    0,                         /* tp_traverse */
    0,                         /* tp_clear */
    0,                         /* tp_richcompare */
    0,                         /* tp_weaklistoffset */
    0,                         /* tp_iter */
    0,                         /* tp_iternext */
    unixSocketsMethods,        /* tp_methods */
    0,                         /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)socketInit,      /* tp_init */
    0,                         /* tp_alloc */
    socketNew,                 /* tp_new */
};

There’s a lot going on here. we define here the class name (“UnixSockets.socket”), constructor, destructor, initializer, and the class methods (unixSocketMethods).
This struct is registered as a Python type in the main function of the module (I will show this later).

Allocator and initializer

These are too different functions. Basically, in normal usage, both will be called when we create a new object, but while the allocator is called only once, upon creation, the initializer is actually the class’s __init__ function, which can be called independently (in some circumstances), and this needs to be taken into consideration – For example, in my code I prevent calling __init__ while the socket is already open (Another way to handle this is to close the socket and re-open it with the new file name).

The allocator

static PyObject *socketNew(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    socket *self;

    self = (socket *)type->tp_alloc(type, 0);
    if (self == NULL)
        return NULL;

    self->fd = 0;

    return (PyObject *)self;
}

This is a simple example of an allocator. We don’t care about the input arguments. We only allocate a new “socket” struct (using an allocator which is implemented by Python), and if the allocation goes well, we initialize the fd and return the allocated struct. This allocated struct will be passed to us later, on each method, as “self”.

The initializer

static int socketInit(socket *self, PyObject *args, PyObject *kwds)
{
    const char *socket_name;

    if (self->fd != 0) {
        PyErr_SetString(PyExc_BaseException,
                        "Cannot initialize an open socket");
        return -1;
    }

    if (!PyArg_ParseTuple(args, "s", &socket_name))
        return -1;

    self->fd = socket_open(socket_name);
    if (self->fd <= 0) {
        PyErr_SetFromErrno(PyExc_IOError);
        return -1;
    }

    return 0;
}

As I explained before, in order to prevent the user from trying to re-open an opened socket, I check if the file descriptor is non-zero. If it is, I raise an exception. There is an extensive API for exceptions handling,  and there’s a list of exception types you can throw.

Our initializer takes one parameter – The socket’s file name, if the parsing of the input tuple fails, the we return -1. Usually, when returning a error value (-1), we must first set an exception, as we do when the fd is not zero, or when socket_open fails. But PyArg_ParseTuple already takes care of this for us.

If socket_open fails, we set the exception message directly from errno, so the user can know exactly what did go wrong.

Deallocator and clear

“tp_clear” is not required in this type, since we don’t have any inner objects which can be visited – I preferred not to expose “fd”, because its value has no meaning at the Python level, but I could have made it a PyObject too, and so allow access to it. In such case, I must implement “tp_traverse” and “tp_clear”, and also add “Py_TPFLAGS_HAVE_GC” to tp_flags (more on this issue – here).

Deallocating is pretty simple:

static void socketDealloc(socket* self)
{
    if (self->fd > 0)
        socket_close(self->fd);

    self->ob_type->tp_free((PyObject*)self);
}

If the file descriptor is valid, then we close the socket, and then we use Python-provided (default) free method.

Class methods

Our class has two methods – “write” and “read” (“open” and “close” are already integrated into the constructor/destructor). If you look at our type’s definition, the tp_methods field is set to “unixSocketsMethods”, and here is how it is defined:

static PyMethodDef unixSocketsMethods[] = {
    { "write", (PyCFunction)socketWrite, METH_VARARGS, "Write to a Unix domain socket" },
    { "read", (PyCFunction)socketRead, METH_NOARGS, "Read from a Unix domain socket" },
    { NULL, NULL, 0, NULL }
};

We declare the method name, and define its callback. Then we define how the function is called, and give a description for the doc.

Write

static PyObject *socketWrite(socket *self, PyObject *args)
{
    const char *str;
    int res, len;

    if (!PyArg_ParseTuple(args, "s#", &str, &len))
        return NULL;

    res = socket_write(self->fd, str, len);
    if (res <= 0) {
        PyErr_SetFromErrno(PyExc_IOError);
        return NULL;
    }

    return Py_BuildValue("i", res);
}

As we declared this method, write takes one parameter – a string, from a tuple. We parse it into a string and its length, and write it to the socket. Upon failure, we set an exception and return NULL – This is how Python knows that the function fails and look for the exception. When we return NULL, we must also set an exception.
If succeeded, we return the number of bytes sent (as a PyObject).

Read

static PyObject *socketRead(socket *self)
{
    char str[MAX_BUFFER_LEN];
    int res;

    res = socket_read(self->fd, str, MAX_BUFFER_LEN);
    if (res <= 0) {
        PyErr_SetFromErrno(PyExc_IOError);
        return NULL;
    }
    str[res] = '\0';

    return Py_BuildValue("s", str);
}

Read takes no arguments. It tries to read a bufer from the socket. On fail, it set an exception and return NULL. When succeeds it terminates the string and returns a copy of it as a PyObject.

Initializing the module

Every Python C module must have a unique PyMODINIT_FUNC function, this function is called when the module is imported (by Python’s “import” directive).

This is how our init function looks like:

PyMODINIT_FUNC initUnixSockets(void)
{
    PyObject* m;

    if (PyType_Ready(&socketType) < 0)
        return;

    m = Py_InitModule3("UnixSockets", unixSocketsModuleMethods,
                       "Unix socket modules");
    if (m == NULL)
        return;

    Py_INCREF(&socketType);
    PyModule_AddObject(m, "Socket", (PyObject *)&socketType);
}

PyType_Ready “finalizes” our object type – Adds some necessary defaults to our new type. Then we register our module – This module doesn’t have any method of it own, so unixSocketsModuleMethods is just a “dummy” array of methods.
PyModule_AddObject registers our new type. We need socket type to have at least one reference for this, so we increment its reference before adding it.

Using the new module

This is how we use our new module (after building and installing it, of courses):

import sys, UnixSockets

if len(sys.argv) != 2:
    print('Usage: python {0} '.format(sys.argv[0]))
    quit()

socketName = sys.argv[1]

try:
    mySocket = UnixSockets.Socket(socketName)
except Exception as e:
    print('Error opening socket {0}: "{1}"'.format(socketName, e))
    quit()

words = [ 'Hi there', 'Just testing you from python', 'Third message', 'Another message, just before leaving', 'So long']

for word in words:
    try:
        writeRes = mySocket.write(word)
        print('* Sent "{0}", {1} bytes sent'.format(word, writeRes))
        resp = mySocket.read()
        print('  Listener response: {0}'.format(resp))
    except IOError as e:
        print('Error communicating with listener: "{0}"'.format(e))
        break

First, we import our library using the “import” directive. This script receives the socket name as a command line argument, and passes it as an argument to the object initializer. We do this inside a try-catch section, and if something goes wrong, we’ll catch the exception and print its error message, and here’s an example:

$ python tests/python/UnixSocket.py /tmp/sock
Error opening socket /tmp/sock: "[Errno 2] No such file or directory"

For the purpose of testing, we go over a list of strings, write each one to the socket, and read the listener’s answer. Again, if we get an exception, we print an error message.
Here’s the output of a successful execution of this script:

$ python tests/python/UnixSocket.py /tmp/sock1
* Sent "Hi there", 8 bytes sent
  Listener response: Recieved 8 Bytes
* Sent "Just testing you from python", 28 bytes sent
  Listener response: Recieved 28 Bytes
* Sent "Third message", 13 bytes sent
  Listener response: Recieved 13 Bytes
* Sent "Another message, just before leaving", 36 bytes sent
  Listener response: Recieved 36 Bytes
* Sent "So long", 7 bytes sent
  Listener response: Recieved 7 Bytes

Exactly what we wanted.

This is it for now,

Amnon.

Git reflog – The git lifesaver

Git command is a very powerful tool, allowing you to do practically everything to the git repository you’re using. As it is powerful, it is also very non-user friendly, even compared to other Linux commands. And so, you can easily f!^k things up.

I’m here to show you a very useful tool, for the case you did something stupid… localy… if you were talented enough to push your mistake (we all have done it at some point), then only the repository’s owner will help you, and you can only hope that he’s mercyfull.
[Actually, you can probably do something like “git revert” and push, but you’re mistake(s) will be visible to all. If someone knows of a “quiet” way of reverting erroneous commits from the remote repository, I’ll be glad to learn]

Introducing “git reflog” – This command will show you a list of the recent operation you have done on the local repository, similar to “git log –oneline”, except instead of a list of commits, you see a list of changes, and each change has a “SHA” – The long hex which uniquely identify it – Just like a commit. All that is left to do in order to revert to the desired point is “git reset –hard <change #>”.

And now, an example.
I created a dummy repository, and a main.c that prints one line of text, here is the our repository’s relog so far:

$ git reflog
0f26690 HEAD@{0}: commit: Add printout
aacbdb6 HEAD@{1}: commit: Add new file: "main.c"
0fc0894 HEAD@{2}: commit (initial): Initial commit

Now I made a “light mistake”, and amended the last commit with changes I did not intend on inserting:

$ vim main.c 
$ git add main.c 
$ git commit --amend
[master e6ea730] Add printout
 Date: Sun Dec 4 00:25:06 2016 +0200
 1 file changed, 3 insertions(+)

Oops… We can fix this by “reset HEAD~1”, erasing the unwanted text, and committing (again) only the wanted code. But it would be easier to fix with relog.
Here’s the reflog:

$ git reflog
  e6ea730 HEAD@{0}: commit (amend): Add printout
  0f26690 HEAD@{1}: commit: Add printout
  aacbdb6 HEAD@{2}: commit: Add new file: "main.c"
  0fc0894 HEAD@{3}: commit (initial): Initial commit

We can see the diff between the last good commit and the “amend” that messed it up:

$ git diff 0f26690 e6ea730
diff --git a/main.c b/main.c
index a29c03d..6c261d7 100644
--- a/main.c
+++ b/main.c
@@ -2,7 +2,7 @@

int main()
{
    -    printf("This is a dummy program\n");
    +    printf("This is a dummy program\n"); this is a mistake

        return 0;
}

And now we can revert to the desired point:

git reset --hard 0f26690
HEAD is now at 0f26690 Add printout

Looking at the log we can see these commits:

$ git log --oneline
0f26690 Add printout
aacbdb6 Add new file: "main.c"
0fc0894 Initial commit

But only the desired changes are in the last commit:

$ git diff 0f26690^!
diff --git a/main.c b/main.c
index 31a1337..a29c03d 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,8 @@
+#include 

int main()
{
    +    printf("This is a dummy program\n");
    +
        return 0;
}

This is, of course, just a simple example. But we can use “reflog” to fix real damage we made by, for example, using “git rebase” (excellent tool for messing up your repository) or by any other means.

Till next time,
Amnon.

C Bindings – Java

This is the second post in this serie. In this post I’m going to show how to create a C library for usage in Java.

Why would we want to do such a thing? Java is a platform-independent language, and C is platform dependent, so when we use a C library in Java, we’re binding ourselves to the platform this library is built for.
But when our project is intended to run on a dedicated platform, there is no such problem, and if this platform has some special hardware, or if we want to enhance our SW performance, we may have to use C. And if this platform runs Android OS, this becomes very useful, as we can develope the low-level stuff in C, and bind it to the application which is always written in Java.

We will make use of the “Java Native Interface” (JNI) framework in order to build our library. “Native” here stands for “platform-specific”. There’s an excellent Wikipedia page on JNI, I recommend reading it.

The code for this post can be found on github.

The header file

First thing we need to do is to include “jni.h”, this file contains all the definition we need for developing a Java module in C. Let’s look at the declaration of the function in our header file, and see some of these definitions:

JNIEXPORT jint JNICALL Java_LinuxSocket_open(JNIEnv *env, jobject obj,
                                             jstring jSocketName);
JNIEXPORT void JNICALL Java_LinuxSocket_close(JNIEnv *env, jobject obj,
                                              jint jSocket);
JNIEXPORT jstring JNICALL Java_LinuxSocket_read(JNIEnv *env, jobject obj,
                                                jint jSocket);
JNIEXPORT jint JNICALL Java_LinuxSocket_write(JNIEnv *env, jobject obj,
                                              jint jSocket, jstring jBuffer);
  • First thing we notice here is “JNIEXPORT” and “JNICALL” – This is how we make a “Java method” out of our C function.
  • Second thing is the function name. The underscores replace the dot operator, so we’re actually creating “Java.LinuxSocket.open”, where “LinuxSocket” is our library and “open” is a method in this library.
  • The first argument to each one of these function is a pointer to “JNIEnv”, this is our “link” to the Java runtime – We can use this parameter for creating and deleting Java objects (such as exceptions and strings), call Java objects’ methods, etc.
    The second parameter is a “jobject”, and this is the object which this method belongs to (we are not making use of it in our code)
  • We can see that we receive and return Java defined types: “jint”, “jstring” and so on.

Implementation

Let’s look at the “open” method:

#define MESSAGE_MAX_SIZE 256

JNIEXPORT jint JNICALL Java_UnixSocket_open(JNIEnv *env, jobject obj,
                                             jstring jSocketName)
{
    char message[MESSAGE_MAX_SIZE];

    const char *socket_name = (*env)->GetStringUTFChars(env, jSocketName, NULL);
    int s = socket_open(socket_name);
    
    if (s <= 0) {         jclass Exception = (*env)->FindClass(env, "java/lang/Exception");
        snprintf(message, MESSAGE_MAX_SIZE, "Couldn't open socket %s", socket_name);
        (*env)->ThrowNew(env, Exception, message);
    }

    (*env)->ReleaseStringUTFChars(env, jSocketName, socket_name);
    return (jint)s;
}

Right on the start we can see usage of the “JNIEnv” parameter. We use it for converting a Java string into a C-Style string. Notice that when we’re finished, we need to release this string, as we do right before we return.
We use “socket_open” which we get out of our marvelous unix-socket-client static library, and then we check for errors Java-style. In Java, a fully object-oriented language, the proper way of handling errors is by throwing an exception. So again, we’re using our “JNIEnv” parameter in order to create an exception object which we’re going to throw.
Even if an exception was thrown, the function is going to continue till its end (unlike the normal behaviour inside Java itself), so we have our chance to release the string before returning. In such case (exception thrown), there will be no meaning for the return value.

The rest of the functions are more or less the same, so we’ll leave them to the reader (as they say in math books), and go ahead to see how we’re going to use this library in Java.

By building our library as a shared object, and installing it at the proper place, we’re making our library available for Java applications.

The Java part

We create a class named “UnixSocket” – Same as our library functions (java.UnixSocket.*).

public class UnixSocket

In its “static” section we load our shared library.

static {
    try {
        System.loadLibrary("unixsockets");
    } catch (UnsatisfiedLinkError e) {
        System.err.println("Error: UnixSockets JNI Library failed to load\n" + e);
        System.exit(1);
    }
 }

The library functions are declared as “native”, so that Java knows that these are implemented in the JNI layer.

native private int open(String socketName);
native private void close(int socket);
native private String read(int socket);
native private int write(int socket, String out);

Our class saves the returned file descriptor as an int (fd). Here is the implementation of the class’s constructor, which calls “open”. Although it looks simple (as it actually is), you can see that it throws an exception. This is the exception we discussed in the C implementation above.

public UnixSocket(String socketName) throws Exception {
    fd = open(socketName);
 }

Testing

As I mentioned, the way I chose to implement this, “open” is called with the class constructor – We pass the socket name to the constructor, then “open” is called. Let’s see how this works out in the test program.

UnixSocket socket;
try {
    socket = new UnixSocket(args[0]);
} catch (Exception e) {
    System.out.println(e.getMessage());
    return;
}

If “open” succeeds, then socket is created successfully, otherwise, “open” (at the very bottom layer) will throw an exception, which is caught here. This exception holds an error message, and we can print it out

Now, the output of the Java test program – The program sends a (silly) string to the listener, and print out the message it got back from the listener:

$ java UnixSocketTest /tmp/socket1
Got response: Recieved 16 Byte
Got response: Recieved 15 Byte
Got response: Recieved 9 Byte
Got response: Recieved 8 Byte

And the output of the listener:

$ ./listenerd /tmp/socket1
[LISTENER] INFO  Starting "Unix Domain Sockets" demo listener
[LISTENER] INFO  * Starting communication with a client *
[LISTENER] INFO  Incoming message: Try this string
[LISTENER] INFO  Incoming message: Maybe this one
[LISTENER] INFO  Incoming message: Have fun
[LISTENER] INFO  Incoming message: Bye bye
[LISTENER] INFO  Client socket was closed by peer

Yes! Everything works!
Till next time,
Amnon.

C Bindings – Lua

This is the first post of a serie I’m going to write on binding C to other programing languages (or script languages – I’m disregarding the differences here).

High-level languages often offer an API for creating libraries written in C. Why would we want this?
One thing is performance – With C you can write performance-oriented code in order to do a specific calculation/operation much faster, and even incorporate assembly code and other machine-specific accelerations. With C we can also optimize the amount of RAM usage.
Another thing is that languages such as Java or Python are not bound to the machine type or OS, and sometimes you want to use features that are unique to the platform you’re working on, like a specific processor features, OS mechanisms or HW features, and using C you can have access to the system’s resources.

And the downside of this is, of course, that we bind our implementation to a specific platform. We can, obviously, compile our C library for every platform we intend our software to run on, but this can be very hard, up to impossible. For example, creating such a library for Java on an Android platform – If you don’t have administrator privileges, and most users don’t, you won’t be able to even install it.

I’m going to show examples for binding C with a few languages. I will use the client side library of the unix sockets example from a previous post, and I will build a client in the particular language, which can communicate with the unix sockets listener.

The code for this serie of posts can be found on github, and it will be updated as I go and add more implementation for other languages.

Lua

Introduction

Lua is a small-footprint scripting language, intended (mostly) for embedded platforms. Although it has a very compact syntax, it is quite powerful. It is developed by the “Pontifical Catholic University of Rio de Janeiro in Brazil”, and has a complete book, free online, for version 5.1 (currently the latest version is 5.3.3), you can find it in the link.
I’m sure, although I didn’t check, that there’s a Lua library for unix domain sockets, but I’m doing this for the exercise.

Including a dynamic library in Lua

In Lua, we include other libraries using “require”, like so:

local sockets = require('somelib')

“somelib” might be either a “.lua” file or a “.so” file. An so file is a dynamic library, which in Lua’s case, uses Lua’s infrastructure and adhere to some special conventions.
Lua’s interpreter looks for the file in a few predefined locations, depending on where Lua is installed (and also in the calling file’s path).

“Unix Sockets” (client) Library

We would like our API to implement these features:

  • “Open”: Function for opening a socket for communication
    Input: Socket “file” name
    Output: Socket Object when pass ; “nil” on fail
  • Socket Object
    Holds the socket’s file descriptor, and implements the following methods:

    • “Write”: Writes data to socket
      Input: Data
      Output: Pass/Fail
    • “Read”: Read data from socket:
      Input: None
      Output: Data/nil
    • “Close”: Close the socket.
      No input nor output

    I’m actually cheating a little here. Lua doesn’t really have objects in its full sense, so all the above methods will have to take the object itself as the first parameter. This object will be implemented using a Lua table (no Lua metatables here – keeping it simple)

Lua “main”

The function that gets called when you require a Lua dynamic library must be in the form of:

int luaopen_somelib(lua_State *L)

Where “somelib” is the exact name of the so (that is “somelib.so”).

“L” has an important role – It holds the arguments’ stack. So we need to “pop” our inputs from it, and “push” our outputs into it. The actual C return value (int) is the number of argument we’re returning Lua-wise, that is, the number of parameters we pushed into the stack.

Our main looks like this:

static const luaL_Reg unix_sockets_lib[] = {
    {"open",  unix_sockets_open },
    {NULL, NULL}
};

int luaopen_libunixsockets(lua_State *L)
{
    luaL_newlib(L, unix_sockets_lib);

    return 1;
}

“luaL_newlib” hides some functionality here. It creates a new Lua table, adds

the functions from”unix_socket_lib” to this table, and pushes this table into the stack.
We return “1” because there’s one return parameter on the stack.

The list of functions itself – “unix_sockets_lib”, contain one function which is the implementation for “open”, and as Lua defines, it is terminated by {NULL, NULL}.

Open

static int unix_sockets_open(lua_State *L)
{
    const char *name = lua_tostring(L, 1);
    int sock = socket_open(name);
    if (sock < 0) {
        lua_pushnil(L);
        return 1;
    }

    lua_newtable(L);
    luaL_setfuncs(L, socket_methods, 0);
    lua_pushinteger(L, sock);
    lua_setfield(L, 2, "fd");

    return 1;
}

The only input parameter for this function is a string, and “lua_tostring” is the function that brings us this parameter from the stack. Similar functions exist for every other Lua type.
We use “socket_open” from our unix_sockets static library in order to open the socket, and if we fail, we push “nil” to the stack, and return 1 (the number of return values).
If the operation passes, however, we create a new table, using “lua_newtable”. This table is automatically pushed into the stack, and the operation we are going to perform on it will be performed inside the stack.
This table is our “socket object”, so we need to attach its methods, and we do this by “luaL_setfuncs”.
Then we want to save the fd in this table. Inserting a new field to a table is done by pushing the field to the stack, and then “merging” it into the table. You see how it goes there – We push the integer, and then we set the field “fd” of the 2nd object in the stack (the table, the 1st is the integer) to be the pushed value.

Notice that Lua library functions has two different prefixes here. The ones starting with “lua” belong to the basic infrastructure included by “lua.h”. The ones starting with “luaL” belong to an extension library, included by “luaxlib.h”.

Write

static int unix_sockets_write(lua_State *L)
{
    int res;
    int sock = lua_getfield(L, 1, "fd");
    const char *buffer = lua_tostring(L, 2);

    res = socket_write(sock, buffer, strlen(buffer));
    if (res <= 0)
        lua_pushnil(L);
    else
        lua_pushboolean(L, 1);
    return 1;
}

As we defined, “write” takes two parameters. The first is the socket “object”, and the second is a string (data).
First, we take extract the fd from the table, “lua_getfield” will do this for us. Then we take out the string using “lua_tostring”.
Then, we use “socket_write” from our library, and push the proper result to the stack – nil upon failure, “true” upon success.

“read” and “close” are based on the same concepts, you can review the code if you want.

The Lua script – Using the C library

As you’ll see, this is quite straightforward. All the real operation are well hidden in the C layer. All we have to do now is call one of our API functions.

Including the library:

local sockets = require('libunixsockets')

Opening a new socket:

local s = sockets.open(sock_name)

Writing/Reading:

local e = sock:write(v)
    if not e then
    print('Failed sending ' .. v .. ' to listener')
    break -- This happens inside a loop
end

local resp = sock:read()
print('* Sent "' .. v .. '", listener reponse: "' .. tostring(resp) .. '"')

Closing:

s:close()

Testing

Here is the output test run of our script:

Opened socket "/tmp/sock1"
* Sent "Test string #1", listener response: "Recieved 14 Bytes"
* Sent "Another try", listener response: "Recieved 11 Bytes"
* Sent "This is the last message in this test!", listener response: "Recieved 38 Bytes"
Socket closed

On the server’s side we’ll see:

$ ./listenerd /tmp/sock1
[LISTENER] INFO  Starting "Unix Domain Sockets" demo listener
[LISTENER] INFO  * Starting communication with a client *
[LISTENER] INFO  Incoming message: Test string #1
[LISTENER] INFO  Incoming message: Another try
[LISTENER] INFO  Incoming message: This is the last message in this test!
[LISTENER] INFO  Client socket was closed by peer
^C[LISTENER] INFO  Terminating service

That’s it, I hope you liked it. In the next post I’ll demonstrate the same for Java.
Amnon.

Unix Domain Sockets

“Unix domain sockets” is a powerful socket-based IPC (inter-process communication) mechanism, it uses the same-old sockets API, and is simple to use… well, it has many features, so getting deep in it might be a bit complicated, but the basic use of Unix domain sockets it quite simple.

The man page is excellent, and it has a very good code example, almost as good as mine 🙂

All the code for this post can be found in github.

Unix-domain server

Basically, we create a “server” by opening a socket (either stream or datagram) and linking it to an address, which is actually a filename in our filesystem*. Then we listen for clients and wait for incoming data. Exactly as we do with network sockets.

* There are other binding options, but I’m going to review the filesystem one here.

In my example code, my listener waits for a client (using “accept”), and when a client connect, it handles the connection until the client closes (not optimal, because a client can starve other clients, but this is only an example).
In order to terminate the listener, it handles “Ctrl-C” – when this signal is received, it exits gracefully.

So, this is what we need to do:

  • Step 1: Create a socket and bind it to an address (a filename)
    1. Creating the socket:
       int sock = socket(AF_UNIX, SOCK_STREAM, 0);

      We are using the “AF_UNIX” family, which is the Unix-domain family, with SOCK_STREAM. We can also use SOCK_DGRAM if we want a datagram socket.

    2. Binding the socket:
       res = bind_address(sock, path);

      Where “sock” is the result from the call to “socket()”, and “path” is the filename that represents the socket. This filename mustn’t exist, therefore, we call “unlink(path)” before calling bind, to be sure that the filename is cleared.

    3. Listen:
       res = listen(sock, MAX_CLIENTS);

      “MAX_CLIENTS” is the length of the clients queue – We’re handling one client at a time.

  • Step 2: In a loop, wait for clients
     while (!quit) {
         int client_socket = accept(sock, NULL, NULL);
         if (client_socket < 0) {          if (errno != EINTR)              continue;          LOGE("Failed accepting client (%d: %s)", errno, strerror(errno));          break;      }      quit = handle_client(client_socket) > 0 ? 1 : 0;
         if (quit) 
             LOGI("Got termination command, exiting");
    
         close(client_socket);
    }
    

    Notes:
    Our socket is blocking, as we didn’t define it otherwise, so “accept()” will block until a client tries to connect.
    We exit only if accept fails on EINTR because we don’t want just any client connection error to kill our service.
    handle_client handles the input/output from/to the client. I defined it, arbitrarily, so that if it returns any positive value, then the listener exits.

    Regarding listener ending, I think it is important to define a SIGTERM handler, so that if the program needs to exit, it will do so gracefully (closing sockets and unlinking the address).

  • Step 3: When a client connects, receive data from it and send back result.
    This is really trivial, and it happens in “handle_client()”. We read the input data like so:

     len = read(sock, buff, MAX_BUFFER_LEN-1);

    Where “sock” is the client socket’s file descriptor that we received from “accept()”.
    Now we do all our processing on the input, and when we want to send data back to the client, we use “write”:

     res = write(sock, out_buff, outbuff_len);

    We can repeat reading/writing as long as the client is connected, and when we decide to terminate the connection, we close the client socket:

     close(client_socket);

Easy enough.

Unix-domain client

Well, this is even easier than creating a server.

  • Step 1: Create a new Unix-domain socket and connect to the server
    1. Creating a new client socket is exactly the same as for the server
    2. Connecting:
      struct sockaddr_un address;
      
      memset(&address, 0x00, sizeof(address));
      address.sun_family = AF_UNIX;
      strncpy(address.sun_path, socket_name, SOCKET_NAME_MAX_LEN);
      
      res = connect(sock, (struct sockaddr *)&address, sizeof(address));
  • Step 2: Read/Write data
    Again, exactly the same as explained above
  • Step 3: Disconnect
    Dito – Use close.

Execution example

Listener

$ ./listener /tmp/sock1
[LISTENER] INFO  Starting "Unix Domain Sockets" demo listener
[LISTENER] INFO  * Starting communication with a client *
[LISTENER] INFO  Incoming message: Test this string
[LISTENER] INFO  Client socket was closed by peer
[LISTENER] INFO  * Starting communication with a client *
[LISTENER] INFO  Incoming message: Take another one
[LISTENER] INFO  Client socket was closed by peer
^C[LISTENER] INFO  Terminating service

Client

$ ./test_client /tmp/sock1 "Test this string"
INFO  Starting "Unix Domain Sockets" demo client
INFO  Got back: Got your message
$ ./test_client /tmp/sock1 "Take another one"
INFO  Starting "Unix Domain Sockets" demo client
INFO  Got back: Got your message

Just what we wanted!
Until next time,
Amnon.

Detecting defective tarballs (from a list of files)

There’s this build system, where tar files are downloaded into a specific folder, and then extracted, compiled and whatever. There are several thread, each one downloads, extracts, compiles and installs, and suddenly, there is no more space left on the hard drive. After a little cleanup for extra space, trying to rebuild fails, because some threads were in the middle of downloading when stopped violently, so a few tar files were corrupted – We need to delete them before going on.

Now, there are tens of files, checking them one by one will take a long time, and will be very tedious, better clean and rebuild, even if it takes a day 🙂

However, we can use a bash script for detecting defected tarballs!

First, how can we tell if a tar file is defected?

Tar’s “-t” option gives us a list of the stored files. It’s pretty quick, and when the file is corrupted, it fails, like so:

$ tar -tf not_a_tar_file.tar.gz 
tar: This does not look like a tar archive

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now

$ echo $?
2

The bash variable “$?” gives us the result of the last execution. “Pass” is (obviously) zero, and any other value is “Fail”. So we can use this information.

Improving this for a single file, we’ll send the output, including stderr, to /dev/null, using a redirection: “&> /dev/null”

Then, all we have to do is to put it into a loop, add some command line input, and we get this short script:

#!/bin/bash

if [ -z "$1" ] ; then
    DIR=`pwd`
else
    ls $1 &> /dev/null
    if [ "$?" -ne "0" ] ; then
        echo "No such path: "$1
        exit 1
    fi

    DIR=$1
fi

FILES_LIST=`ls $DIR`
for FILE in $FILES_LIST ; do
    FULLNAME=$DIR/$FILE 
    tar -tf $FULLNAME &> /dev/null
    if [ "$?" -eq "0" ] ; then
        echo $FULLNAME" is OK" 
    else
        echo "[!]" $FULLNAME "is defiective"
    fi
done

And its execution looks like this:

$ ./verify_my_tarballs.sh ./list

./list/backup.tar.gz is OK
[!] ./list/not_a_tar_file.tar.gz is defiective
./list/one_tar.tar.gz is OK
./list/onther_one.tar.gz is OK
./list/project1.tar.gz is OK

Notice that this script is good only for tar files. We can probably expand it to handle zip files and other archive file types, by using the same concept

* No tar files were harmed during the making of this post.

Amnon.

Using rtnetlink for detection of NICs status changes in C

I had a task once, where I had to update a configuration when a change was detected in the network interfaces. While the major part of the task was the configuration part, it’s interesting to see how we can detect networking changes in C, and it’s also a nice Netlink exercise.

Netlink is a socket-based IPC between the kernel and user-space, using packets communication (a datagram-oriented service). Netlink communication in user-space is done with the standard and familiar sockets API, similar to unix-domain sockets and INET sockets (See Netlink’s man page).

Netlink has a lot of families, which are sort of sub-protocols. Each family is designed for communication with a different kernel service. It also has a generic family, for user-customized communication.

What I’m going to show here is the usage of “RTNL” – Routing Netlink. This Netlink family is used for managing the routing services of the kernel. We can send commands to change routing, get routing information or “subscribe” for routing notification as (RTNL man page).

The complete code for this post can be downloaded from github.

Netlink messages

An incoming buffer from a netlink socket can contain one or more netlink messages. Each message consists of a header and payload. It looks something like this:

This is the header structure, I think it is pretty self-documenting:

struct nlmsghdr {
    __u32 nlmsg_len;    /* Length of message including header. */
    __u16 nlmsg_type;   /* Type of message content. */
    __u16 nlmsg_flags;  /* Additional flags. */
    __u32 nlmsg_seq;    /* Sequence number. */
    __u32 nlmsg_pid;    /* Sender port ID. */
};

The message payload itself depends on the type, as we’ll soon see with RT messages.

Netlink API offers convenient macros to iterate the messages, extract the payload, and such. You should use them instead of doing the casting yourself, since netlink uses strict alignments, which the macros already take into account.

More on netlink can be found in it’s man page. Or here, if you want to go deeper into Netlink.

RT Netlink

If we are receiving RT Netlink messages, nlmsg_type will indicate which routing message it is, and the payload will match the type. RT Netlink payload look something like this:

The “Message data” is a struct (as I said, it depends on the netlink message type), and the attributes struct looks like this:

struct rtattr {
    unsigned short rta_len;    /* Length of option */
    unsigned short rta_type;   /* Type of option */
    /* Data follows */
};

And here, again, the attribute’s data depends on the attribute’s type.

In our example, we wait for “RTM_NEWLINK” netlink message type, which payload is this:

struct ifinfomsg {
    unsigned char  ifi_family; /* AF_UNSPEC */
    unsigned short ifi_type;   /* Device type */
    int            ifi_index;  /* Interface index */
    unsigned int   ifi_flags;  /* Device flags  */
    unsigned int   ifi_change; /* change mask */
};
  • We will be interested only in messages that inform a change in network interfaces, that is, only messages with non-zero ifi_change.
  • ifi_flags will indicate if the device was taken up, or down.
  • In order to know which interface has changed its state, we’ll look for an attribute with rta_type “IFLA_IFNAME”, and read its payload, which type is char*.

Taking it into practice

Opening a netlink socket with RT netlink family is shown in the man page, and looks like this:

fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

Binding the socket to a specific “Netlink address” – Here we specify which RT groups we want to “subscribe” to. We can subscribe to more than one by OR’ing them together. Here we subscribe only to “RTMGRP_LINK”:

sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_LINK;
err = bind(fd, (struct sockaddr *) &sa, sizeof(sa));

Waiting for messages and receiving data is done with the regular sockets API. In my code I used “poll” and “recv”, but any other API will do. You can see this part in the code itself.

When we get the message buffer, we need to iterate the netlink messages it contains by iterating the header:

for (nh = (struct nlmsghdr *)buff; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
    .
    .
    .

And for each message we look for nlmsg_type “RTM_NEWLINK” with change indication:

    ifi = NLMSG_DATA(nh);
    if (nh->nlmsg_type != RTM_NEWLINK || !ifi->ifi_change)
        continue;

If we do find such a message, we iterate its attributes in order to find the interface’s name:

char *if_name = NULL;

for ( ; RTA_OK(rta, rta_len) ; rta = RTA_NEXT(rta, rta_len)) {
    if (rta->rta_type == IFLA_IFNAME) {
        if_name = (char*)RTA_DATA(rta);
        break;
    }
}

Where rta and rta_len is taken from the netlink message:

struct rtattr *rta = IFLA_RTA(ifi);
int rta_len = IFLA_PAYLOAD(nh);

Again, you can check out the code itself for the complete picture, I believe it’s clear enough.

Amnon.

Amnon

Advantures in Embeddedland · Post

Update Revert to draft Preview Close

ComposeHTML

Normal
Labels
C, C++, devices, linux, netlink, network interfaces, networking, nic, programming, rtnetlink, sockets, unix
Published on

5/20/16, 10:36 PM

Israel Daylight Time

Permalink
Location
Search Description
Options

Amnon

Advantures in Embeddedland · Post

Update Revert to draft Preview Close

ComposeHTML

Normal
Labels
C, C++, devices, linux, netlink, network interfaces, networking, nic, programming, rtnetlink, sockets, unix
Published on

5/20/16, 10:36 PM

Israel Daylight Time

Permalink
Location
Search Description
Options

Amnon

Advantures in Embeddedland · Post

Update Revert to draft Preview Close

ComposeHTML

Normal
Labels
C, C++, devices, linux, netlink, network interfaces, networking, nic, programming, rtnetlink, sockets, unix
Published on

5/20/16, 10:36 PM

Israel Daylight Time

Permalink
Location
Search Description
Options

Amnon

Advantures in Embeddedland · Post

Update Revert to draft Preview Close

ComposeHTML

Normal
Labels
C, C++, devices, linux, netlink, network interfaces, networking, nic, programming, rtnetlink, sockets, unix
Published on

5/20/16, 10:36 PM

Israel Daylight Time

Permalink
Location
Search Description
Options