[Pkg-gnu-smalltalk-devel] Bug#497033: gnu-smalltalk: FTBFS on GNU/kFreeBSD

Paolo Bonzini bonzini at gnu.org
Fri Aug 29 13:03:03 UTC 2008


> This structure have to be different on BSDs.
> I am unable to fix it my self.

I see why the fix in experimental does not work.  Apparently BSD systems
actually do not care much about the content of sa_len, it's just that it
is there.  I had tested the fix with Mac OS on a big-endian PowerPC.  So
sa_len was always 0, but sa_family was set correctly.  On little-endian
systems it's the other way round, and sa_family is set incorrectly to 0.

I'm now always passing to C sockaddrs with sa_len, and removing the
sa_len on platforms that do not have it.

2008-08-29  Paolo Bonzini  <bonzini at gnu.org>

        * IP6SocketImpl.st: Fill in sa_len dutifully for BSD systems.
        * IPSocketImpl.st: Fill in sa_len dutifully for BSD systems.
        * UnixSocketImpl.st: Fill in sa_len dutifully for BSD systems.
        * sockets.c: Undo the above dutifully for non-BSD systems.


diff --git a/build-aux/sockets.m4 b/build-aux/sockets.m4
index 3020534..2f62e83 100644
--- a/build-aux/sockets.m4
+++ b/build-aux/sockets.m4
@@ -25,6 +25,9 @@ AC_CHECK_MEMBER([struct addrinfo.ai_family],
                           [Define if your system's netdb.h has struct
addrinfo])], [],
                [#include <netdb.h>])

+dnl This is wrong for Windows, but anyway Windows does not have sa_len
+AC_CHECK_MEMBERS([struct sockaddr.sa_len], , , [#include <sys/socket.h>])
+
 if test "$ac_cv_lib_ws2_32_listen" = "yes"; then
     gst_cv_sockets=yes
 fi
diff --git a/packages/sockets/IP6SocketImpl.st
b/packages/sockets/IP6SocketImpl.st
index 4c043a2..d437632 100644
--- a/packages/sockets/IP6SocketImpl.st
+++ b/packages/sockets/IP6SocketImpl.st
@@ -248,8 +248,9 @@ stream (TCP), datagram (UDP) and raw sockets.'>
                with: address
                startingAt: 1;

-           "Write sin_family = AF_INET in host order"
-           shortAt: 1 put: self class addressFamily;
+            "Write sin_len and sin_family = AF_INET6"
+            at: 1 put: 28;
+            at: 2 put: self class addressFamily;

            "Write sin_port in network order (big endian)"
            at: 3 put: port // 256;
diff --git a/packages/sockets/IPSocketImpl.st
b/packages/sockets/IPSocketImpl.st
index b298d80..f1837a7 100644
--- a/packages/sockets/IPSocketImpl.st
+++ b/packages/sockets/IPSocketImpl.st
@@ -315,8 +315,9 @@ stream (TCP), datagram (UDP) and raw sockets.'>
                with: address
                startingAt: 1;

-           "Write sin_family = AF_INET in host order"
-           shortAt: 1 put: self class addressFamily;
+           "Write sin_len and sin_family = AF_INET"
+           at: 1 put: 16;
+           at: 2 put: self class addressFamily;

            "Write sin_port in network order (big endian)"
            at: 3 put: port // 256;
diff --git a/packages/sockets/UnixSocketImpl.st
b/packages/sockets/UnixSocketImpl.st
index 794c5ef..58b6ddd 100644
--- a/packages/sockets/UnixSocketImpl.st
+++ b/packages/sockets/UnixSocketImpl.st
@@ -138,8 +138,9 @@ a String or a File object.
        portString size > 108
            ifTrue: [self error: 'socket path too long'].
        ^(ByteArray new: 110)
-           "Write sin_family = AF_INET in host order"
-           shortAt: 1 put: self class addressFamily;
+            "Write sin_len and sin_family = AF_UNIX"
+            at: 1 put: portString size + 2;
+            at: 2 put: self class addressFamily;
            replaceFrom: 3 to: portString size + 2 with: portString
startingAt: 1;
            yourself
     ]
diff --git a/packages/sockets/sockets.c b/packages/sockets/sockets.c
index a7cc1a1..c34b1b5 100644
--- a/packages/sockets/sockets.c
+++ b/packages/sockets/sockets.c
@@ -270,9 +270,25 @@ mySocket (int domain, int type, int protocol)
   return fd;
 }

+
+/* BSD systems have sa_len, others have not.  Smalltalk will always
+   write sockaddr structs as if they had it.  So for Linux and Winsock
+   we read the second byte (sa_family on BSD systems) and write it in the
+   entire sa_family field. */
+static inline void
+fix_sockaddr (struct sockaddr *sockaddr)
+{
+#ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
+  /* Make sure sa_family is a short.  */
+  char verify[sizeof (sockaddr->sa_family) == 2 ? 1 : -1];
+
+  sockaddr->sa_family = ((unsigned char *) sockaddr)[1];
+#endif
+}
+
 /* Same as connect, but forces the socket to be in non-blocking mode */
 static void
-myConnect (int fd, const struct sockaddr *sockaddr, int len)
+myConnect (int fd, struct sockaddr *sockaddr, int len)
 {
   SOCKET sock = FD_TO_SOCKET (fd);
 #ifdef __MSVCRT__
@@ -286,6 +302,7 @@ myConnect (int fd, const struct sockaddr *sockaddr,
int len)
     fcntl (sock, F_SETFL, oldflags | O_NONBLOCK);
 #endif

+  fix_sockaddr (sockaddr);
   connect (sock, sockaddr, len);
   if (is_socket_error (EINPROGRESS))
     errno = 0;
@@ -299,8 +316,9 @@ myAccept (int fd, struct sockaddr *addr, int *addrlen)
 }

 static int
-myBind (int fd, const struct sockaddr *addr, int addrlen)
+myBind (int fd, struct sockaddr *addr, int addrlen)
 {
+  fix_sockaddr (addr);
   return bind (FD_TO_SOCKET (fd), addr, addrlen);
 }

@@ -345,8 +363,9 @@ myRecvfrom (int fd, char *buf, int len, int flags,
struct sockaddr *from,

 static int
 mySendto (int fd, const char *buf, int len, int flags,
-         const struct sockaddr *to, int tolen)
+         struct sockaddr *to, int tolen)
 {
+  fix_sockaddr (to);
   return sendto (FD_TO_SOCKET (fd), buf, len, flags, to, tolen);
 }

@@ -355,6 +374,7 @@ mySetsockopt (int fd, int level, int optname, const
char *optval, int optlen)
 {
   return setsockopt (FD_TO_SOCKET (fd), level, optname, optval, optlen);
 }
+
 static int
 getSoError (int fd)
 {


Blaaargh.

Paolo





More information about the Pkg-gnu-smalltalk-devel mailing list