The Corelatus Blog
E1/T1 and SDH/SONET telecommunications

Porting C socket code to Windows

Posted June 16th 2010

I just ported the C example code for controlling Corelatus E1/T1 hardware to Visual Studio 2010. Doing that was easier than expected. This first part of this post is about how to use that code. The second part is a bit of history about what I had to do to port the code.

Obtaining Visual Studio

Microsoft have their C/C++ compiler available for free download on microsoft.com

The install process is pretty standard for windows, if you're accustomed to Microsoft products, there are no surprises here.

Compiling the code

  1. Start the "Visual Studio Command Prompt". By default, that's in "Start/Programs/Microsoft Visual Studio 2010 Express".
  2. Navigate to the directory you unpacked the sample code in. Remove any old .exe files with 'del *.exe'.
  3. Run 'nmake /f NMakefile'. After a couple of seconds, you have six brand-new .exe files. Here's what this step looks like:
screenshot of a VC compile

If you just wanted to see how to compile the code, you can stop reading now. The rest of the post is just about what I had to do to make this work with Microsoft's compiler.

Hurdle #1: MS nmake vs gnumake vs Visual Studio projects

Conclusion: I ended up using Microsoft's nmake and wrote a separate NMakefile for it.

My code gets built by 'make', through a Makefile. Visual Studio doesn't include a make program which can understand normal Makefiles, leaving me a choice of either using the Visual Studio IDE or using Microsoft's nmake.

I spent half an hour trying the IDE route. When you make a new project, you have to choose what sort it is. "CLR Console Application" seemed closest to what I wanted to do, so I chose that. Maybe "Makefile Project" would have worked better. Things got increasingly confusing from there. What's a "solution?" Why are "precompiled headers" enabled? I just want to compile a few hundred lines of C. At that point, I gave up, the IDE is clearly not the easiest way for me to get started.

Next, I tried Microsoft's replacement for make, called nmake. That didn't start flawlessly either, nmake uses its own syntax. Initially, I thought I might be able to write one Makefile which both gnumake and nmake understand. But Microsoft's syntax seems to be too different to allow that. Oh well. The NMakefile is just a dozen lines or so.

Hurdle #2: Missing header files

Conclusion: I used #ifdefs to include different header files when compiling in a win32 environment.

Visual Studio doesn't provide some of the header files the code uses, e.g. there's no 'unistd.h' and no 'sys/socket.h'. Odd. Providing most of unistd.h shouldn't be too hard.

The point of this exercise is to get the code to compile using a Microsoft toolchain, so I didn't investigate using cygwin or mingw.

In the end, it turns out that I wasn't using anything from 'unistd.h' which didn't get provided by something else in win32. 'socket.h' (and friends) was a bit harder, but it turns out that's provided by 'winsock2.h'.

Hurdle #3: 'Mostly compatible' socket API

Conclusion: winsock2 is different to the BSD socket API, but the differences can be worked around with just a few changes.

Sockets were invented on unix, so I assumed that other OSes would just copy the interface. But no, not on win32. There seem to be at least two attempts to make a socket API for windows, called 'winsock' and 'winsock2'. The first seems to be deprecated. The main problems I hit were:

None of those problems are hard to get around.

Hurdle #4: GNU and Microsoft can't agree on function names

Both GNU and Microsoft have replacements for some functions which are prone to security problems. If you use plain strcat() or strcpy, visual studio warns about security problems.

Disabling the warnings would be quick but feels like cheating. So I looked at the 'less insecure' alternatives. GNU call them strncat and strncpy whereas Microsoft call them strcat_s and strcpy_s. And the arguments are the same way around. It would have been nice if GNU and MS had solved this the same way, but no. Minor annoyance.

Hurdle #5: Structure packing pragmas

Conclusion: Both MS and GNU understand the #pragma pack(N) syntax, but only GNU understands the __attribute__((__packed__)) syntax.

A couple of the examples (save_to_pcap.c and record.c) use structures to encode or decode data defined by an external format. For instance, here's what the wire format of a 'Pcap' protocol capture file looks like:

    
      typedef struct {
        unsigned int magic;
        unsigned short major_version;
        unsigned short minor_version;
        unsigned int GMT_to_localtime;
        unsigned int sigfigs;
        unsigned int snaplen;
        unsigned int network;
      } PCAP_global_header;
    
  

We have to tell the compiler that spacing out the fields to get a certain alignment isn't allowed. The recommended GNU way to do that is to add __attribute__((__packed__)) after the structure. The recommended Microsoft way is to add #pragma pack(1) somewhere before the structure, and then remember to change the packing back again before hitting any code which is sensitive to performance.

Since this is just example code, we don't care about that last bit of performance, so we can just leave the packing at 1.

Aside: the structure above is a bit sloppy because just quietly assumes that an int is 32 bits and a short 16.

Hurdle #6: Windows firewall

Some of the example code opens TCP sockets for listening. By default, the windows firewall doesn't allow that. Just click "fine, ok, let me do this".

Unfortunately, that looks ugly for the user---the program will fail the first time you run it, and the pop-up box says "publisher unknown". Does anyone know how to improve on this? It'd be nice if the user could approve the publisher, i.e. me, once, and then every program works.

How long did the porting take?

A couple of days, including getting Visual Studio installed. That's for a few thousand lines of code with a bit of socket IO and file IO.

If I had to do it again, it'd take an afternoon or so.

Permalink | Tags: GTH, C, Windows