FAQ

Most of the questions in this FAQ are, genuinely, frequently asked questions compiled from the various discussions I've had about the library over the years.

This FAQ is updated periodically. If there's a question you think belongs here, drop me an e-mail and I'll do my best to answer it.



1. Branding

1.1. Why lacewing?

Lacewing is the common name for the Chrysopidae, a very cool looking insect that happens to be fast and lightweight.

The logo is a vector graphic drawn by Jean Villy Edberg in 2011.

He's called Eugene, and he's licensed under a Creative Commons Attribution 3.0 Unported License. An SVG can be found in the art directory.

1. The Project

2.1. How many people are working on this?

The bulk of the library is written by myself, James McLaughlin. A list of contributors is available in the AUTHORS file.

The library also incorporates a lot of third party code such as http-parser, multipart-parser-c and uthash (all, like liblacewing, under a BSD or MIT license).

2.2. How did this start?

The library was originally developed in 2006 to facilitate the development of a networking layer for Multimedia Fusion 2, a game development tool produced by Clickteam. It was then released as open source in January 2011, following a substantial effort further developing the webserver under NetworkTronics as the backend for a web application.

Today, development continues independently of any commercial incentive.

2.3. Don't we already have libraries for networking?

Of course we do - but, as with any other field, there's no “one true way” an API for networking should be structured, and every library has its own set of quirks, features and limitations.

My motivation for working on liblacewing is that I'm developing the library I want to use. And with any luck, that means other developers might quite like working with it, too.

2.4. Wait, a webserver? Aren't you trying to do too much?

Maybe, but here are a few reasons the HTTP server is sticking around:

2.5. So if there's a HTTP server, why not a HTTP client?

libcurl is a very good HTTP client, and not something we have a reason to compete with.

Better integration of libcurl with lw_eventpump and friends might be a good future project.

2.6. Is this stable enough for production code?

We're still pre-1.0.0, so by definition not production-ready. I won't make any claims about stability.

2.7. Why BSD and not (L)GPL?

I believe that proprietary software isn't going anywhere, and shouldn't be forced to reinvent the wheel. Encouraging proprietary software to adopt open source by using permissive licenses is a good thing.

The GPL suggestion that everyone who uses a piece of code wants to make a closed source fork and never contribute back is unrealistic. BSD-licensed projects receive contributions for the right reasons: contribute code upstream, and you don't have to maintain it yourself.

3. The Code

3.1. Why GitHub?

GitHub is quickly becoming industry standard for project hosting. And it's really awesome.

3.2. Why C and not C++?

I try to be pragmatic about this. The library code itself wouldn't benefit from C++ features, but I understand how ugly it can be to use a C library in C++. That's why a complete set of C++ wrappers around the C functions are provided and maintained as part of the core library.

3.3. Three space indent? Seriously?

Yes, it's a bit eccentric. But four was too long, two was too short and three was juuust right. ;-)

In all seriousness, you should be able to configure your editor to work with a three space indent quite easily, if it doesn't do this automatically. You might even start to like it...

3.4. Why not use a build system like CMake or SCons?

I'm sure they're brilliant, but our more boring setup with autoconf and (GNU) make seems to be adequate for the time being. GNU make is required because (and this is stupid) the syntax for conditionals is slightly different compared to BSD make, and GNU make is the more common of the two.

The only major issue with our current build system is keeping the Visual Studio project in synchronization with the Makefile, but we don't really add or remove source files often enough for this to be a problem.

3.5. Can't the C++ wrappers be auto-generated?

They could be, but since they're all there already, it'd just be a waste of time writing a generator. Besides, some of the functions in the C++ API are intentionally slightly different from their C counterparts.

It's possible that we might look into doing something with SWIG in the future, which is something we weren't able to use before due to the lack of support for nested classes.

3.6. What are you using for SSL?

SChannel on Windows, OpenSSL everywhere else. We're probably one of the few projects out there using SChannel for SSL (I believe libcurl recently added support?)

Cryptic API aside, it seems to work pretty well. The biggest limitation is the lack of support for TLS Next Protocol Negotiation, which means we don't currently support the SPDY protocol on Windows.

3.7. Why did you typedef e.g. lw_stream to lw_stream *?

This one is controversial, because it makes it unclear that lw_stream is actually a pointer.

I did it this way because user code can never actually use a real lw_stream, because that struct definition is internal to the library. Without the typedef, every single occurrence of lw_stream in user code would have to be written as lw_stream *, which makes the * redundant.

(Note that lw_stream was just used as an example here; this applies to all liblacewing classes.)

3.8. Why is the Windows and UNIX code completely separate? Isn't this code duplication?

If you've worked with raw sockets before, you might be wondering why we did this when Berkeley socket code seems to work just fine on Windows. Well, the truth is that Berkeley-style sockets on Windows are just a wrapper over the real Winsock, and that wrapper is severely limited.

IF YO

4. Structure

4.1. Why is there a lw_eventpump?

If you're a UNIX developer, you can think of lw_eventpump as the liblacewing answer to select(2). The application plugs liblacewing classes into it, and then (through one of several usage patterns) sets it to work watching for things happening and pumping events around the library.

One of the key design issues is that not all applications are the same, and lw_eventpump has to respect that. A game can't run lw_eventpump_start_eventloop and have the whole main thread blocked forever, and that's why we have lw_eventpump_tick. A Win32 GUI application already has a blocking message pump, so lw_eventpump_start_sleepy_ticking is provided.

Also, you don't have to use lw_eventpump. The lw_pumpdef structure is a set of function pointers defining what a pump has to be able to do, so if you can implement those for your own event loop, the liblacewing classes should play ball.

4.2. How does lw_stream compare to other implementations of a “stream”?

You're probably familiar with the concept of a stream from elsewhere: it's something you can write data to, and read data from. In liblacewing, pretty much everything is a stream, which is standard for an I/O library.

However, there are a few things that set liblacewing streams apart:

4.3. Why can't I have a SOCKET or a file descriptor?

You should assume there isn't one. Reading or writing to the underlying socket would subvert the stream model, and it probably wouldn't be compatible with the dark magic we do to achieve consistency across different platforms.

4.4. Can I attach my own data to liblacewing classes?

Most classes have _tag and _set_tag functions:

          void* lw_stream_tag                   (lw_stream);
          void  lw_stream_set_tag               (lw_stream, void *);
        

These can be used to store and retrieve a pointer of your choice (for example, a pointer to your own structure).

4.6. How can I implement my own stream?

Populate a lw_streamdef structure with function pointers to your own stream functions, and pass it to lw_stream_new to retrieve a lw_stream instance.

At the time of writing, a description of each function in lw_streamdef is currently missing from the documentation. Some example stream implementations to work from:

4.6. I'm implementing a stream. What's tail_size in lw_streamdef?

It lets lw_stream_new know how much memory you want allocating after the lw_stream structure, which you can use to store your own data without taking over the tag.

There are two functions to work with this:

           lw_import void * lw_stream_tail (lw_stream);
           lw_import lw_stream lw_stream_from_tail (void *);
        

Where lw_stream_tail returns a pointer to the data after the lw_stream, and lw_stream_from_tail returns the lw_stream from the pointer to the data.

4.7. Why is there a lw_client_new but not a lw_client_delete?

Only the base object has a delete function. Anything that derives from lw_stream is deleted with lw_stream_delete, and similarly anything that derives from lw_pump is deleted with lw_pump_delete.

4.8. Can I use liblacewing in a Qt application without blocking the Qt eventloop?

Yes, this can be accomplished using the sleepy ticking API. An example can be found here.

5. Future

5.1. What's next for liblacewing?

Probably some kind of support for multi-threading, but it's not yet clear how this will be implemented or what advantages it will bring.

5.2. What, ultimately, are you trying to achieve?

liblacewing is a solution to a current problem, and its survival is entirely dependent on whether the languages and platforms of today survive in the future.

There's no ultimate goal for this project: computers only function through layer upon layer of abstraction, and we're just trying to abstract over something that's commonly done and hard to get right. And, with any luck, there'll be some good ideas in the process.

5.3. How can I contribute?

We need help in a lot of areas. In particular: