GNAT.Sockets Sockaddr-structures do not match with C-structures

Petri Rokka petri.rokka at tut.fi
Sun Oct 26 23:28:36 UTC 2008


Hi!

I had some problems with sending an UDP packet via GNAT.Sockets.
The Socket_Send procedure kept raising exception with message like this:
  "Error [125]: Address family not supported by protocol family"

There was also a problem with binding an IP address to the local socket.

Environment that was used: 
 - RTEMS 4.9
 - GCC 4.3.2 (with RTEMS patches)
 - NXP LPC2468 ARM7 (little-endian)
 - Self made ethernet driver

To find the cause of the problem I added some debug messages to 
the GNAT.Sockets files and to the RTEMS networking code. I discovered 
that the protocol family information did not transfer intact to the 
C-socket API. In fact the C-sendto function got always the value 
zero instead of two(AF_INET).

I did some more tracing and noticed that the C-structures and Ada-
structures differed with the size of protocol family variable and that 
there was also an extra length variable in the C-structures. C-structures
had protocol family variable of size 8bits while the GNAT.Sockets had size 
of 16bits. The extra length variable had size of 8bits maybe to compensate
with smaller protocol family variable.

I modified the Ada-structures to match with the C-structures and
there were no problems anymore. 

Could it be possible that this bug does not affect big-endian hosts?


Ada-structures (from gcc/ada/g-socthi.ads) with modifications
-------------------------------------------------------------
  type Sockaddr is record
     Sa_Len    : C.unsigned_char;  -- added
     Sa_Family : C.unsigned_char;  -- changed from C.unsigned_short

     Sa_Data   : C.char_array (1 .. 14);
  end record;
  pragma Convention (C, Sockaddr);

  type Sockaddr_In is record
     Sin_Len    : C.unsigned_char       := 0;                 -- added
     Sin_Family : C.unsigned_char       := Constants.AF_INET; -- changed from C.unsigned_short

     Sin_Port   : C.unsigned_short      := 0;
     Sin_Addr   : In_Addr               := Inaddr_Any;
     Sin_Zero   : C.char_array (1 .. 8) := (others => C.char'Val (0));
  end record;
  pragma Convention (C, Sockaddr_In);


C-structures for comparison:
-----------------------------
  cpukit/libnetworking/rtems/bsdnet/_types.h:typedef      uint8_t         __sa_family_t;

  cpukit/libnetworking/sys/socket.h-struct sockaddr {
  cpukit/libnetworking/sys/socket.h-      unsigned char   sa_len;                 /* total length */
  cpukit/libnetworking/sys/socket.h:      sa_family_t     sa_family;              /* address family */
  cpukit/libnetworking/sys/socket.h-      char    sa_data[14];            /* actually longer; address value */
  cpukit/libnetworking/sys/socket.h-};

  cpukit/libnetworking/netinet/in.h-/* Socket address, internet style. */
  cpukit/libnetworking/netinet/in.h-struct sockaddr_in {
  cpukit/libnetworking/netinet/in.h-      uint8_t sin_len;
  cpukit/libnetworking/netinet/in.h:      sa_family_t     sin_family;
  cpukit/libnetworking/netinet/in.h-      in_port_t       sin_port;
  cpukit/libnetworking/netinet/in.h-      struct  in_addr sin_addr;
  cpukit/libnetworking/netinet/in.h-      char    sin_zero[8];
  cpukit/libnetworking/netinet/in.h-};


Regards
Petri Rokka




More information about the users mailing list