Posts tagged programming

DHCP Servers: Stock routers’, Microsoft Windows ICS’s, Mac OS X’s

MS Windows and Mac OS X let’s you share your internet from one network interface to another one. i.e. You can share your Wireless internet to your Ethernet port. In Windows it is called ICS (Internet Connection Sharing). In Mac OS X, you can do it in the Sharing section for your settings. Not surprisingly, Mac OS X UI is much more intuitive.

In a few days, we’ll be in an industrial automation fair and only available internet connection there will be Wireless. We want to connect our devices to internet there but our devices only have Ethernet port. So we’ll rely on connection sharing of one of these OSes. The problem is that their DHCP servers are acting a bit different than a stock router you’d have.

Windows does not give responses quickly, after my DHCP REQUEST message, it takes a like 1-2 seconds to get ACK message back. And Windows’s DHCP server keeps sending OFFERs and ACKs like crazy for the previously received messages even though an IP address is acquired already. Tweaking the timeouts and making sure my client does not honor OFFERs once that state is passed fixed the issues with Windows’ DHCP server.

However the issue with the Mac was a more subtle one. My device couldn’t acquire IP address at all. I checked if my Windows laptop could get an IP from it and, not surprisingly, it could! My device couldn’t even get an OFFER for its DISCOVER message. I compared Windows’ DISCOVER message with mine to find the differences. There were two differenes:

  1. Seconds field
  2. Options field
First I tried to make the Options field identical. Of course, Murphy’s laws applied and it turned out that it is because of Seconds field. When I changed my Seconds field from 0 to 4 (like Windows do) it all worked out with Mac’s DHCP server.
According to RFC 2131‘s Section 2, page 10, the Seconds field is for:

secs 2 Filled in by client, seconds elapsed since client began address acquisition or renewal process.

I don’t see how this affects the behavior but it fixes the issue.

See also previous mistake I made about DHCP.

Cheers

Macros in C/C++, the right way.

When used appropriately macros are very useful, yet they are very easy to misuse. Before getting into cons and pros, first lets make sure if we really know what is a macro and how does it work.

Roughly there are three stages of compilation in C; preprocessing, compiling, linking. It really makes sense and it is very easy to understand, don’t think of this as a complex deal. We’ll mostly talk about the preprocessor stage in this post. As the name implies, this stage just pre-processes the source code before compiling it, it all happens prior to compiling and that’s it. Preprocessing includes defining some macros, and replacing each macro found in the source code with its value, so that it can be compiled. So get this right once and for all, macros are processed before compilation, they won’t be in the run-time code.

As an exercise you can use -E parameter of GCC, which will make it stop right after the preprocessing stage.

Now, let’s begin with a few examples;

#define ERROR_SEEK 152
if( errno == ERROR_SEEK )
{
    // Handle the error.
}

This directive defines a macro ERROR_SEEK. Preprocessor will replace every occurrences of ERROR_SEEK with 152 prior to compiling. So, the code that is going to be sent to compiler will have “if( errno == 152)” not the ERROR_SEEK because the compiler simply does not know what ERROR_SEEK is. Nothing fancy, dead simple. But it makes the code much more readable. Look at this example;

#ifdef __GNUC__
#define COMPILER "gcc"
#else
#define COMPILER "proprietary"
#endif

If __GNUC__ is defined somehow then every occurrences of COMPILER will be replaced with “gcc” and “proprietary” otherwise. Please note that this all happens before compilation, and this will not result in any executable code. In this special case __GNUC__ is defined by GCC itself. Though we can define a macro via #define directive in the source code, or with -D parameter of the compiler (which will work on most compilers).

Actually the name preprocessor says it all. All these preprocessor directives are pre processed before compilation. Makes sense uh ? Now I think we begin to understand the nature of macros/preprocessors.

Macros can be used to

  • Improve readability (ERROR_SEEK is much more meaningful than 152)
  • Improve maintainability (When you change ERROR_SEEK in one header, it will be replaced all over the source code)
  • Ensuring that a block of code is inlined (more on this later)

Though, if misused, the first two list items above will do  just the opposite :)

As for the possible disadvantages of preprocessors

  • Could make debugging harder as lines of source lines before and after the preprocessing will be different, so debugger can be confused while stepping the executable code and matching which source line of code it is.
  • It is easy to misuse preprocessors.
  • Could cause trouble to static code analyzers.

Now, possible misuse scenarios:

1. Operator precedence

The most common misuse scenario which you’ll see in almost every C book is this;

#define FOO_CONST 83+22
printf("%d\n", FOO_CONST * 5 ); // This macro will expand to 83 + 22 *  5, hence will result 193.

One could expect the result to be printed 525. But operator precedence would make the calculation 22 * 5 first, then add 83 to the result, so you’ll see 193 as a result instead of 525. Fixing this problem is easy;

#define FOO_CONST (83+22)
printf("%d\n", FOO_CONST * 5 ); // This macro will expand to (83+22) * 5, hence will result 525.

Enclosing the value of a macro is an easy way to ensure that they are evaluated in the right order.

2. Multiple statements

You can use multiple-statement macros to force inlining of a code block. Though note that this will increase the code size of your program. Anyway, the problem with the multiple-statements is a less known problem. Now, look at this.

#define HELLO(X) printf("Hello "); printf( X "\n" );

The problem with this code is, if you want to conditionally run this code with “if” this code will not do what you intend to do.

if(0)
    HELLO("world"); // You'd expect that this HELLO() is never "executed".

Above code will expand into

if(0)
    printf("Hello ");
printf( "world" "\n" );

As you can see in the above example only the first statement in the macro is conditionally executed, this is not what we intended for. Above code will always print “world\n”.

So, first thing comes to mind is to put them in curly brackets. Now let’s evaluate that.

#define HELLO(X) { printf("Hello "); printf( X "\n" ); }

Above code looks fine at first glance, but it will also introduce a sneaky bug that will result in compilation error. Now imagine above macro is used like this;

if(1)
    HELLO("world");
else
    HELLO("baby");

This will expand into;

if(1)
{
    printf("Hello ");
    printf("world" "\n");
}; // WE GOT ERROR HERE
else
{
    printf("Hello ");
    printf("baby" "\n");
};

So, here’s the trick which works perfectly. It is the do{} while(0) trick. OK, let’s see.

#define HELLO(X) do { printf("Hello "); printf( X "\n"); } while(0)

You can use this as you please, imagine the if else scenario.

if(1)
    HELLO("world");
else
    HELLO("baby");

This will expand into;

if(1)
    do { printf("Hello "); printf( "world" "\n" ); } while(0);
else
    do { printf("Hello "); printf( "baby" "\n" ); } while(0);

So do {} while(0) does not break when you place a semi-colon after it and also has a scope. So it’s a ideal for making sure your multiple-statements are executing as you expected.

Well, I guess that’s all I’ve got to say.

Go to Top