1

I'm making a network server in C and trying to define packet handlers as generic as possible.

When I receive a completed packet, I want to create a struct and send it to the defined handler.

struct handler {
   char *msg_name;
   void (*handler)(network_client *, void *msg).
}

//global variable containing all handlers
struct handler const handlers[] = {
   {"hello_msg", &helloMessageHandler}
};

struct hello_message_s {
   int foo;
   char *bar;
   float foobar;
}

//called when received hello_cmd and deserialized hello_message_s bytes received by the network
void helloMessageHandler(network_client *c, void *msg) {
   struct hello_message_s *casted = msg;

   casted->foo; //etc..
}

My question is; is there a way to specify the message struct directly instead of void * forcing me to cast later? i.e change void helloMessageHandler(network_client *c, void *msg) to void helloMessageHandler(network_client *c, struct hello_message_s *msg).

It's not possible since handlers[] can hold handlers with void * only.

struct handler const handlers[] = {
   {"hello_msg", &helloMessageHandler}
};

Any solution?

lordjj
  • 29
  • 5
  • How do you create a struct in order to pass it to the handler? You need to know the struct's definition, no? So there is a coupling between the deserialiser and the handler... – rici Jun 08 '18 at 15:26
  • each message will have a serialize and deserialize function and its associated handler. deserialize could return a void * – lordjj Jun 08 '18 at 15:28
  • I think I have to play around casts – lordjj Jun 08 '18 at 15:31
  • If deserialise returns a void*, it's logical that the handler accepts a void*, surely? That's the C way, in any event. If you wanted to avoid type-erasure, you'd be using a different language. My point was that if you have a mapping from name to handler, and then presumably a mapping from name to deserializer, then type-erasure prevents you from representing (and thus enforcing) the type coupling between the two functions. Void* at least makes that fact apparent. – rici Jun 08 '18 at 15:43
  • See https://stackoverflow.com/questions/19165134/correct-portable-way-to-interpret-buffer-as-a-struct – Doug Currie Jun 08 '18 at 15:55

1 Answers1

0

If you have only a finite number of structs describing a packet, you can use union including all the packets instead of void *.

But usage of void * is more common, as far as I know. The downside of using union is that its size will be equal to the largest member of the union.

Anton Malyshev
  • 8,686
  • 2
  • 27
  • 45