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