New FileDescriptorHandle and SocketHandle stuff.
authorStefan Vogel <sv@exept.de>
Fri, 21 Dec 2001 17:42:00 +0100
changeset 6350 ccfbaa0daaee
parent 6349 e2129a5fe59e
child 6351 2ba7efbf2aab
New FileDescriptorHandle and SocketHandle stuff.
UnixOperatingSystem.st
--- a/UnixOperatingSystem.st	Fri Dec 21 17:36:26 2001 +0100
+++ b/UnixOperatingSystem.st	Fri Dec 21 17:42:00 2001 +0100
@@ -47,6 +47,13 @@
 	privateIn:UnixOperatingSystem
 !
 
+UnixOperatingSystem::FileDescriptorHandle subclass:#SocketHandle
+	instanceVariableNames:''
+	classVariableNames:'ProtocolCache'
+	poolDictionaries:''
+	privateIn:UnixOperatingSystem
+!
+
 !UnixOperatingSystem primitiveDefinitions!
 %{
 
@@ -488,8 +495,551 @@
 # endif
 #endif
 
+
+/*
+ * Socket defines
+ */
+
+
+#if defined(transputer)
+# define NO_SOCKET
+#endif
+
+/*
+ * which protocols can we support ?
+ */
+#ifndef NO_SOCKET
+# define WANT__AF_INET
+#endif
+
+#define WANT__AF_UNIX
+
+#ifdef __VMS__
+# undef WANT__AF_UNIX
+# define WANT_AF_DECnet
+#endif
+
+
+#ifdef LINUX
+/* kludge to avoid some redefines ... */
+# define _ARPA_NAMESER_H
+# define _NETINET_TCP_H
+#endif
+
+#if !defined(NO_SOCKET)
+# if defined(IRIS) && !defined(IRIX5)
+   /* no socket.h on 4.0.5h ?!?!? */
+#  ifndef AF_UNIX
+#   define AF_UNIX 1
+#  endif
+#  ifndef AF_INET
+#   define AF_INET 2
+#  endif
+
+#  ifndef SOCK_STREAM
+#   define SOCK_STREAM 1
+#  endif
+#  ifndef SOCK_DGRAM
+#   define SOCK_DGRAM  2
+#  endif
+#  ifndef SOCK_RAW
+#   define SOCK_RAW    3
+#  endif
+# else
+#  include <sys/socket.h>
+# endif
+
+# ifdef NEXT3
+#  include <netinet/in_systm.h>
+# endif
+#endif
+
+
+/*
+ * see what we want ...
+ */
+#ifdef WANT__AF_UNIX
+# ifdef AF_UNIX
+#  ifndef PF_UNIX
+#   define PF_UNIX AF_UNIX
+#  endif
+# endif
+#else
+# undef AF_UNIX
+#endif
+
+#ifdef WANT__AF_INET
+# ifdef AF_INET
+#  ifndef PF_INET
+#   define PF_INET AF_INET
+#  endif
+# endif
+#else
+# undef AF_INET
+#endif
+
+#ifdef WANT__AF_INET6
+# ifdef AF_INET6
+#  ifndef PF_INET6
+#   define PF_INET6 AF_INET6
+#  endif
+# endif
+#else
+# undef AF_INET6
+#endif
+
+#ifdef WANT__AF_DECnet
+# ifdef AF_DECnet
+#  ifndef PF_DECnet
+#   define PF_DECnet AF_DECnet
+#  endif
+# endif
+#else
+# undef AF_DECnet
+#endif
+
+#ifdef WANT__AF_APPLETALK
+# ifdef AF_APPLETALK
+#  ifndef PF_APPLETALK
+#   define PF_APPLETALK AF_APPLETALK
+#  endif
+# endif
+#else
+# undef AF_APPLETALK
+#endif
+
+#ifdef WANT__AF_X25     /* X.25 */
+# ifdef AF_X25
+#  ifndef PF_X25
+#   define PF_X25 AF_X25
+#  endif
+# endif
+#else
+# undef AF_X25
+#endif
+
+#ifdef WANT__AF_NS      /* Xerox XNS */
+# ifdef AF_NS
+#  ifndef PF_NS
+#   define PF_NS AF_NS
+#  endif
+# endif
+#else
+# undef AF_NS
+#endif
+
+#ifdef WANT__AF_SNA     /* IBM SNA */
+# ifdef AF_SNA
+#  ifndef PF_SNA
+#   define PF_SNA AF_SNA
+#  endif
+# endif
+#else
+# undef AF_SNA
+#endif
+
+#ifdef WANT__AF_RAW     /* RAW packets */
+# ifdef AF_RAW
+#  ifndef PF_RAW
+#   define PF_RAW AF_RAW
+#  endif
+# endif
+#else
+# undef AF_RAW
+#endif
+
+#ifdef WANT__AF_ISO     /* ? */
+# ifdef AF_ISO
+#  ifndef PF_ISO
+#   define PF_ISO AF_ISO
+#  endif
+# endif
+#else
+# undef AF_ISO
+#endif
+
+#ifdef WANT__AF_NETBIOS /* NETBIOS */
+# ifdef AF_NETBIOS
+#  ifndef PF_NETBIOS
+#   define PF_NETBIOS AF_NETBIOS
+#  endif
+# endif
+#else
+# undef AF_NETBIOS
+#endif
+
+#ifdef WANT__AF_CCITT /* ? */
+# if defined(AF_CCITT) && (AF_CCITT != AF_X25)
+#  ifndef PF_CCITT
+#   define PF_CCITT AF_CCITT
+#  endif
+# endif
+#else
+# undef AF_CCITT
+#endif
+
+#ifdef WANT__AF_IPX /* Novell IPX */
+# ifdef AF_IPX
+#  ifndef PF_IPX
+#   define PF_IPX AF_IPX
+#  endif
+# endif
+#else
+# undef AF_IPX
+#endif
+
+#ifdef WANT__AF_AX25 /* Amateur Radio AX.25 */
+# ifdef AF_AX25
+#  ifndef PF_AX25
+#   define PF_AX25 AF_AX25
+#  endif
+# endif
+#else
+# undef AF_AX25
+#endif
+
+#ifdef WANT__AF_NETROM /* Amateur Radio NET/ROM */
+# ifdef AF_NETROM
+#  ifndef PF_NETROM
+#   define PF_NETROM AF_NETROM
+#  endif
+# endif
+#else
+# undef AF_NETROM
+#endif
+
+#ifdef WANT__AF_BRIDGE /* multiprotocol bridge */
+# ifdef AF_BRIDGE
+#  ifndef PF_BRIDGE
+#   define PF_BRIDGE AF_BRIDGE
+#  endif
+# endif
+#else
+# undef AF_BRIDGE
+#endif
+
+#ifdef WANT__AF_BSC /* BISYNC 2780/3780 */
+# ifdef AF_BSC
+#  ifndef PF_BSC
+#   define PF_BSC AF_BSC
+#  endif
+# endif
+#else
+# undef AF_BSC
+#endif
+
+#ifdef WANT__AF_ROSE /* Amateur Radio X.25 PLP */
+# ifdef AF_ROSE
+#  ifndef PF_ROSE
+#   define PF_ROSE AF_ROSE
+#  endif
+# endif
+#else
+# undef AF_ROSE
+#endif
+
+#ifdef WANT__AF_ATM /* ATM Services */
+# ifdef AF_ATM
+#  ifndef PF_ATM
+#   define PF_ATM AF_ATM
+#  endif
+# endif
+#else
+# undef AF_ATM
+#endif
+
+#ifdef WANT__AF_BAN /* BAN / VINES IP Services */
+# ifdef AF_BAN
+#  ifndef PF_BAN
+#   define PF_BAN AF_BAN
+#  endif
+# endif
+#else
+# undef AF_BAN
+#endif
+
+#ifdef WANT__AF_VOICEVIEW /* VoiceView Services W95 only */
+# ifdef AF_VOICEVIEW
+#  ifndef PF_VOICEVIEW
+#   define PF_VOICEVIEW AF_VOICEVIEW
+#  endif
+# endif
+#else
+# undef AF_VOICEVIEW
+#endif
+
+#ifdef WANT__AF_IRDA /* infrared */
+# ifdef AF_IRDA
+#  ifndef PF_IRDA
+#   define PF_IRDA AF_IRDA
+#  endif
+# endif
+#else
+# undef AF_IRDA
+#endif
+
+
+/*
+ * now, include what we have to ...
+ * undef support, if no include file is present
+ * (or I dont know yet, where to find it)
+ */
+
+#ifdef AF_UNIX
+# ifdef UNIX
+#  include <sys/un.h>
+# else
+#  undef AF_UNIX
+# endif
+#endif
+
+#ifdef AF_INET
+# include <netdb.h>
+# if defined(PRE_SUSE_7_2)
+#  if defined(LINUX) && defined(AF_INET6)
+#   include <linux/in.h>
+#  else
+#   include <netinet/in.h>
+#  endif
+# else
+#  include <netinet/in.h>
+# endif
+# if !defined(LINUX)
+#  if ! (defined(SYSV3) && defined(mc88k))
+#   include <netinet/tcp.h>
+#  endif
+# endif
+#endif
+
+#ifdef AF_INET6
+# if defined(LINUX) && defined(__GLIBC__)
+#  if defined(PRE_SUSE_7_2)
+#   include <linux/in6.h>
+#  endif
+# else
+#  undef AF_INET6
+# endif
+#endif
+
+#ifdef AF_APPLETALK
+# ifdef LINUX
+#  include <asm/types.h>
+#  include <linux/atalk.h>
+# else
+#  undef AF_APPLETALK
+# endif
+#endif
+
+#ifdef AF_DECNET
+# ifdef solaris2_0
+#  include <X11/dni8.h>
+# else
+#  undef AF_DECNET
+# endif
+#endif
+
+#ifdef AF_X25
+# ifdef LINUX
+#  include <linux/x25.h>
+# else
+#  undef AF_X25
+# endif
+#endif
+
+#ifdef AF_AX25
+# ifdef LINUX
+#  include <linux/ax25.h>
+# else
+#  undef AF_AX25
+# endif
+#endif
+
+#ifdef AF_IPX
+# ifdef LINUX
+#  include <linux/ipx.h>
+# else
+#  ifdef WIN32
+#   include <wsipx.h>
+#  else
+#   undef AF_IPX
+#  endif
+# endif
+#endif
+
+#ifdef AF_NETBIOS
+# ifdef WIN32
+#  include <wsnetbs.h>
+# else
+#  undef AF_NETBIOS
+# endif
+#endif
+
+#ifdef AF_ATM
+# ifdef WIN32
+#  include <ws2atm.h>
+# else
+#  undef AF_ATM
+# endif
+#endif
+
+#ifdef AF_BAN
+# ifdef WIN32
+#  include <wsvns.h>
+# else
+#  undef AF_BAN
+# endif
+#endif
+
+#ifdef AF_VOICEVIEW
+# ifdef WIN32
+#  include <wsvv.h>
+# else
+#  undef AF_VOICEVIEW
+# endif
+#endif
+
+#ifdef AF_IRDA
+# ifdef LINUX
+#  include <linux/irda.h>
+# else
+#  undef AF_IRDA
+# endif
+#endif
+
+#undef AF_SNA     /* not yet implemented */
+#undef AF_RAW     /* not yet implemented */
+#undef AF_NETROM  /* not yet implemented */
+#undef AF_BRIDGE  /* not yet implemented */
+#undef AF_BSC     /* not yet implemented */
+
+
+/*
+ * see what is leftOver
+ */
+union sockaddr_u {
+#ifdef AF_UNIX
+        struct sockaddr_un un;
+#endif
+#ifdef AF_INET
+        struct sockaddr_in in;
+#endif
+#ifdef AF_INET6
+        struct sockaddr_in6 in6;
+#endif
+#ifdef AF_APPLETALK
+        struct sockaddr_at at;
+#endif
+#ifdef AF_DECNET
+        struct sockaddr_dn dn;
+#endif
+#ifdef AF_X25
+        struct sockaddr_x25 x25;
+#endif
+#ifdef AF_AX25
+        struct sockaddr_ax25 ax25;
+#endif
+#ifdef AF_IPX
+        struct sockaddr_ipx ipx;
+#endif
+#ifdef AF_NETBIOS
+        struct sockaddr_nb nb;
+#endif
+#ifdef AF_ATM
+        struct sockaddr_atm atm;
+#endif
+#ifdef AF_BAN
+        struct sockaddr_vns vns;
+#endif
+#ifdef AF_VOICEVIEW
+        struct sockaddr_vv vv;
+#endif
+#ifdef AF_IRDA
+        struct sockaddr_irda irda;
+#endif
+};
+
+
+#if defined(TRY_AGAIN) || defined(HOST_NOT_FOUND)
+# define USE_H_ERRNO
+#endif
+
+#ifdef USE_H_ERRNO
+# ifndef h_errno
+ extern h_errno;
+# endif
+#endif
+
+/*
+ * gethostbyname seems to have trouble
+ * sometimes, if interrupted while a request
+ * is on its way the name server.
+ * (although specified in the man-page, 
+ * a check on TRY_AGAIN fails on iris)
+ */
+#ifdef LINUX
+
+# define GETHOSTBYNAME(hp, name) \
+        hp = gethostbyname((char *) name);
+
+# define GETHOSTBYADDR(hp, addr, alen, af) \
+        hp = gethostbyaddr(addr, alen, af);
+
+#else
+
+# ifdef IRIX5_3
+#  define GETHOSTBYNAME(hp, name) \
+        do { \
+            __BEGIN_INTERRUPTABLE__  \
+            hp = gethostbyname((char *) name); \
+            __END_INTERRUPTABLE__ \
+        } while ((hp == NULL) && \
+                 ((h_errno == TRY_AGAIN) || (errno == ECONNREFUSED)));
+
+#  define GETHOSTBYADDR(hp, addr, alen, af) \
+        do { \
+            __BEGIN_INTERRUPTABLE__ \
+            hp = gethostbyaddr(addr, alen, af); \
+            __END_INTERRUPTABLE__ \
+        } while ((hp == NULL) && \
+                ((h_errno == TRY_AGAIN) || (errno == ECONNREFUSED)));
+# else
+#  ifdef USE_H_ERRNO
+#   define GETHOSTBYNAME(hp, name) \
+        do { \
+            __BEGIN_INTERRUPTABLE__  \
+            hp = gethostbyname((char *) name); \
+            __END_INTERRUPTABLE__ \
+        } while ((hp == NULL) && (h_errno == TRY_AGAIN));
+
+#   define GETHOSTBYADDR(hp, addr, alen, af) \
+        do { \
+            __BEGIN_INTERRUPTABLE__  \
+            hp = gethostbyaddr(addr, alen, af); \
+            __END_INTERRUPTABLE__ \
+        } while ((hp == NULL) && (h_errno == TRY_AGAIN));
+#  else
+#   define GETHOSTBYNAME(hp, name) \
+        __BEGIN_INTERRUPTABLE__  \
+        hp = gethostbyname((char *) name); \
+        __END_INTERRUPTABLE__ 
+
+#   define GETHOSTBYADDR(hp, addr, alen, af) \
+        __BEGIN_INTERRUPTABLE__ \
+        hp = gethostbyaddr(addr, alen, af); \
+        __END_INTERRUPTABLE__
+#  endif
+# endif
+#endif
+
+#ifdef DEBUG
+# define DBGPRINTF(x)    { if (__debugging__) printf x; }
+# define DBGFPRINTF(x)   { if (__debugging__) fprintf x; }
+#else
+# define DBGPRINTF(x)    /* as nothing */
+# define DBGFPRINTF(x)   /* as nothing */
+#endif
+
 %}
-
 ! !
 
 !UnixOperatingSystem primitiveFunctions!
@@ -7554,6 +8104,17 @@
     "Modified: 22.4.1996 / 13:14:46 / cg"
 ! !
 
+!UnixOperatingSystem class methodsFor:'socket creation'!
+
+socketWithDomain:domainArg type:typeArg protocol:protocolArg 
+    "set up socket with domain, type and protocol number.
+     This is a low level entry; no binding, listening or connect
+     is done. Both arguments must be symbols from one of
+     #inet,#unix, #appletalk, #x25 .. and #stream, #datagram, #raw resp."
+
+    ^ SocketHandle new domain:domainArg type:typeArg protocol:protocolArg
+! !
+
 !UnixOperatingSystem class methodsFor:'time and date'!
 
 computeDatePartsOf:osTime for:aBlock
@@ -8639,22 +9200,20 @@
     "return the number of bytes available for reading, without blocking."
 
 %{
-#ifdef NOTDEF   /* does not work ... */
     /*
      * if available, try FIONREAD first, which is usually done faster.
      */
 # if defined(FIONREAD)
     {
-	int n;
-
-	if (__isSmallInteger(fd)) {
-	    if (ioctl(__intVal(fd), FIONREAD, &n) >= 0) {
-		RETURN (__MKINT(n));
-	    }
-	}
+        int n;
+
+        if (__isSmallInteger(fd)) {
+            if (ioctl(__intVal(fd), FIONREAD, &n) >= 0) {
+                RETURN (__MKINT(n));
+            }
+        }
     }
 # endif /* FIONREAD */
-#endif
 %}.
     ^ (self readCheck:fd) ifTrue:[1] ifFalse:[0]
 !
@@ -8665,22 +9224,23 @@
      This depends on a working select or FIONREAD to be provided by the OS."
 
 %{
-#ifdef NOTDEF   /* does not work ... */
     /*
      * if available, try FIONREAD first, which is usually done faster.
      */
-# if defined(FIONREAD)
-    {
-	int n;
-
-	if (__isSmallInteger(fd)) {
-	    if (n = ioctl(__intVal(fd), FIONREAD)) {
-		printf("FIONREAD returns %d\n", n);
-	    }
-	}
+# ifdef FIONREAD
+    if (__isSmallInteger(fd)) {
+        int result = 0;
+
+        if (ioctl(__smallIntegerVal(fd), FIONREAD, &result) >= 0) {
+            printf("FIONREAD returns %d\n", result);
+            if (result > 0) {
+                RETURN(true);
+            } else {
+                RETURN(false);
+            }
+        }
     }
 # endif /* FIONREAD */
-#endif
 %}.
 
     ^ super readCheck:fd
@@ -9268,77 +9828,6 @@
 
 !UnixOperatingSystem::FileDescriptorHandle methodsFor:'misc functions'!
 
-canReadWithoutBlocking
-    "return true, if data is available on a filedescriptor 
-     (i.e. read is possible without blocking).
-     This depends on a working select or FIONREAD to be provided by the OS."
-
-%{
-    /*
-     * if available, try FIONREAD first, which is usually done faster.
-     */
-# ifdef FIONREAD
-    {
-        int n;
-
-        if (__isSmallInteger(__INST(fd))) {
-            if (n = ioctl(__intVal(__INST(fd)), FIONREAD)) {
-                printf("FIONREAD returns %d\n", n);
-            }
-        }
-    }
-# endif /* FIONREAD */
-
-# ifdef __VMS__
-#  ifdef DOES_NOT_WORK_YET
-    {
-        /*
-         * do a sys$qio ..
-         * fd here is suposed to be a channel nr.
-         */
-        struct IOSB iosb;
-        int status;
-        int channel;
-        struct typahdask sensebuf;
-
-        if (__isSmallInteger(fd)) {
-            channel = __intVal(fd);
-            status = SYS$QIO(0, /* efn */
-                             channel,
-                             IO$_SENSEMODE | IO$M_TYPEAHDCNT,
-                             &iosb,
-                             0, /* ast */
-                             0, /* ast arg */
-                             &sensebuf,         /* data */
-                             sizeof(sensebuf),  /* data size */
-                             0, 0, 0, 0);
-            if (status != SS$_NORMAL) {
-                fprintf(stderr, "OS [info]: SYS$QIO failed on %d\n", channel);
-            } else {
-                fprintf(stderr, "sys$QIO -> %d\n", sensebuf.typcnt);
-            }
-        }
-    }
-#  endif
-# endif /* __VMS__ */
-%}.
-
-    OperatingSystem supportsSelect ifFalse:[
-        "/ mhmh - what should we do then ?
-        "/ For now, return true as if data was present,
-        "/ and let the thread fall into the read.
-        "/ It will then (hopefully) be desceduled there and
-        "/ effectively polling for input.
-
-        ^ true
-    ].
-
-    ^ (OperatingSystem selectOnAnyReadable:(Array with:fd)
-                       writable:nil
-                       exception:nil
-                       withTimeOut:0) == fd
-!
-
 seekTo:newPosition from:whence
     "seek to newPosition
      whence is one of: #begin #current #end.
@@ -9488,6 +9977,92 @@
 
 !UnixOperatingSystem::FileDescriptorHandle methodsFor:'queries'!
 
+canReadWithoutBlocking
+    "return true, if data is available on a filedescriptor 
+     (i.e. read is possible without blocking).
+     This depends on a working select or FIONREAD to be provided by the OS."
+
+%{
+    int fd;
+
+    if (__isSmallInteger(__INST(fd))) {
+        fd = __smallIntegerVal(__INST(fd));
+
+        /*
+         * if available, try FIONREAD first, which is usually done faster.
+         */
+# ifdef FIONREAD
+        {
+            int result = 0;
+
+            if (ioctl(fd, FIONREAD, &result) >= 0) {
+                RETURN(result > 0 ? true : false);
+            }
+        }
+# endif /* FIONREAD */
+
+# if defined(__VMS__) && defined(DOES_NOT_WORK_YET)
+        {
+            /*
+             * do a sys$qio ..
+             * fd here is suposed to be a channel nr.
+             */
+            struct IOSB iosb;
+            int status;
+            int channel;
+            struct typahdask sensebuf;
+
+            status = SYS$QIO(0, /* efn */
+                             fd,
+                             IO$_SENSEMODE | IO$M_TYPEAHDCNT,
+                             &iosb,
+                             0, /* ast */
+                             0, /* ast arg */
+                             &sensebuf,         /* data */
+                             sizeof(sensebuf),  /* data size */
+                             0, 0, 0, 0);
+            if (status != SS$_NORMAL) {
+                fprintf(stderr, "OS [info]: SYS$QIO failed on %d\n", fd);
+            } else {
+                fprintf(stderr, "sys$QIO -> %d\n", sensebuf.typcnt);
+            }
+        }
+# endif /* __VMS__ */
+    }
+%}.
+
+    OperatingSystem supportsSelect ifFalse:[
+        "/ mhmh - what should we do then ?
+        "/ For now, return true as if data was present,
+        "/ and let the thread fall into the read.
+        "/ It will then (hopefully) be desceduled there and
+        "/ effectively polling for input.
+
+        ^ true
+    ].
+
+    ^ (OperatingSystem selectOnAnyReadable:(Array with:fd)
+                       writable:nil
+                       exception:nil
+                       withTimeOut:0) == fd
+
+    "
+     |h n|
+     h := OperatingSystem openFileForRead:'/etc/hosts'.
+     n := h canReadWithoutBlocking.
+     h close.
+     n
+    "
+
+    "
+     |h n|
+     h := OperatingSystem openFileForRead:'/dev/ttyS0'.
+     n := h canReadWithoutBlocking.
+     h close.
+     n
+    "
+!
+
 canWriteWithoutBlocking
     "return true, if filedescriptor can be written without blocking"
 
@@ -9511,6 +10086,36 @@
      a file or some other OS object"
 
     ^ fd notNil
+!
+
+numAvailableForRead
+    "return the number of bytes available for reading, without blocking."
+
+%{
+    /*
+     * if available, try FIONREAD first, which is usually done faster.
+     */
+# if defined(FIONREAD)
+    {
+        int n = 0;
+
+        if (__isSmallInteger(__INST(fd))) {
+            if (ioctl(__smallIntegerVal(__INST(fd)), FIONREAD, &n) >= 0) {
+                RETURN (__MKINT(n));
+            }
+        }
+    }
+# endif /* FIONREAD */
+%}.
+    ^ self canReadWithoutBlocking ifTrue:[1] ifFalse:[0]
+
+    "
+     |h n|
+     h := OperatingSystem openFileForRead:'/etc/hosts'.
+     n := h numAvailableForRead.
+     h close.
+     n
+    "
 ! !
 
 !UnixOperatingSystem::FileDescriptorHandle methodsFor:'registering'!
@@ -9623,7 +10228,7 @@
 !UnixOperatingSystem::FilePointerHandle class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.107 2001-12-19 13:58:03 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.108 2001-12-21 16:42:00 stefan Exp $'
 ! !
 
 !UnixOperatingSystem::FilePointerHandle methodsFor:'release'!
@@ -9932,9 +10537,1286 @@
     "Modified: 28.12.1995 / 14:13:41 / stefan"
 ! !
 
+!UnixOperatingSystem::SocketHandle class methodsFor:'constants'!
+
+domainCodeOf:aSymbolOrInteger
+
+    |domainCode|
+
+%{ /*NOCONTEXT*/
+     int code = -1;
+
+     if (__isSmallInteger(aSymbolOrInteger) || aSymbolOrInteger == nil) {
+        RETURN(aSymbolOrInteger);
+     }
+#ifdef AF_INET
+     else if (aSymbolOrInteger == @symbol(inet)) 
+        code = AF_INET;
+#endif
+#ifdef AF_INET6
+     else if (aSymbolOrInteger == @symbol(inet6))
+        code = AF_INET6;
+#endif
+#ifdef AF_UNIX
+     else if (aSymbolOrInteger == @symbol(unix))
+        code = AF_UNIX;
+#endif
+#ifdef AF_APPLETALK
+     else if (aSymbolOrInteger == @symbol(appletalk))
+        code = AF_APPLETALK;
+#endif
+
+     if (code > 0)
+         domainCode = __MKSMALLINT(code);
+%}.
+
+    ^ domainCode.
+
+    "
+     self domainCodeOf:#inet
+     self domainCodeOf:#unix
+     self domainCodeOf:#inet6
+     self domainCodeOf:#appletalk
+    "
+!
+
+domainSymbolOf:anInteger
+
+    |domainSymbol|
+
+%{ /*NOCONTEXT*/            
+
+    if (__isSmallInteger(anInteger)) {
+        switch(__intVal(anInteger)) {
+#ifdef AF_INET
+        case AF_INET:
+            domainSymbol = @symbol(inet);
+            break;
+#endif
+#ifdef AF_INET6
+        case AF_INET6:
+            domainSymbol = @symbol(inet6);
+            break;
+#endif
+#ifdef AF_UNIX
+        case AF_UNIX:
+            domainSymbol = @symbol(unix);
+            break;
+#endif
+#ifdef AF_APPLETALK
+        case AF_APPLETALK:
+            domainSymbol = @symbol(appletalk);
+            break;
+#endif
+        }
+    }
+%}.
+
+    ^ domainSymbol.
+
+    "
+     self domainSymbolOf:(self domainCodeOf:#inet)
+     self domainSymbolOf:(self domainCodeOf:#inet6)
+     self domainSymbolOf:(self domainCodeOf:#unix)
+     self domainSymbolOf:(self domainCodeOf:#appletalk)
+    "
+!
+
+protocolCodeOf:aNameOrNumber
+    "convert a symbol to a numeric protocol code"
+
+    |protocolCode protocolSymbol|
+
+%{
+    if (__isSmallInteger(aNameOrNumber) || aNameOrNumber == nil) {
+        RETURN(aNameOrNumber);
+    }
+%}.
+
+    ProtocolCache notNil ifTrue:[
+        protocolCode := ProtocolCache at:aNameOrNumber asSymbol 
+                                      ifAbsent:[].
+        protocolCode notNil ifTrue:[
+            ^ protocolCode.
+        ].
+    ].
+
+%{
+#ifndef NO_SOCKET
+    struct protoent *protoent = 0;
+
+    if (__isString(aNameOrNumber) || __isSymbol(aNameOrNumber)) {
+        protoent = getprotobyname((char *) __stringVal(aNameOrNumber));
+        if (protoent) {
+            protocolCode = __MKSMALLINT(protoent->p_proto);
+            protocolSymbol = __MKSYMBOL(protoent->p_name, 0);
+        }
+    }
+#endif /*NO_SOCKET*/
+%}.
+
+    protocolSymbol notNil ifTrue:[
+        ProtocolCache isNil ifTrue:[
+            ProtocolCache := IdentityDictionary new.
+        ].
+        "beware of polluting the protocol cache with aliases"
+        ProtocolCache at:protocolSymbol put:protocolCode.
+    ].
+    ^ protocolCode
+
+    "
+     self protocolCodeOf:#tcp
+     self protocolCodeOf:#udp
+     self protocolCodeOf:#raw
+    "
+!
+
+protocolSymbolOf:anInteger
+    "convert a numeric protocol code to a symbol"
+
+    |protocolSymbol|
+
+    ProtocolCache notNil ifTrue:[
+        protocolSymbol := ProtocolCache keyAtIdentityValue:anInteger 
+                                        ifAbsent:[].
+        protocolSymbol notNil ifTrue:[
+            ^ protocolSymbol.
+        ].
+    ].
+
+%{ 
+#ifndef NO_SOCKET
+    struct protoent *protoent = 0;
+
+    if (__isSmallInteger(anInteger)) {
+        protoent = getprotobynumber(__intVal(anInteger));
+        if (protoent) {
+            protocolSymbol = __MKSYMBOL(protoent->p_name, 0);
+        }
+    }
+#endif /*NO_SOCKET*/
+%}.
+
+    protocolSymbol notNil ifTrue:[
+        ProtocolCache isNil ifTrue:[
+            ProtocolCache := IdentityDictionary new.
+        ].
+        ProtocolCache at:protocolSymbol put:anInteger.
+    ].
+    ^ protocolSymbol
+
+
+    "
+     self protocolSymbolOf:(self protocolCodeOf:#tcp)
+     self protocolSymbolOf:(self protocolCodeOf:#udp)
+     self protocolSymbolOf:(self protocolCodeOf:#icmp)
+    "
+!
+
+socketAddressSize:aSymbol
+    "answer the os specific size of a socket address for domain aSymbol"
+
+    |socketSize|
+
+%{ /*NOCONTEXT*/
+     int size = -1;
+
+#ifdef AF_INET
+     if (aSymbol == @symbol(inet)) 
+        size = sizeof(struct sockaddr_in);
+#endif
+#ifdef AF_INET6      
+     else if (aSymbol == @symbol(inet6))
+        size = sizeof(struct sockaddr_in6);
+#endif
+#ifdef AF_UNIX
+     else if (aSymbol == @symbol(unix))
+        size = sizeof(struct sockaddr_un);
+#endif
+#ifdef AF_APPLETALK
+     else if (aSymbol == @symbol(appletalk))
+        size = sizeof(struct sockaddr_at);
+#endif
+
+     if (size > 0)
+         socketSize = __MKSMALLINT(size);
+%}.
+    ^ socketSize
+!
+
+socketTypeCodeOf:aSymbolOrInteger
+
+    |typeCode|
+
+%{ /*NOCONTEXT*/
+     int code = -1;
+
+     if (__isSmallInteger(aSymbolOrInteger) || aSymbolOrInteger == nil) {
+        RETURN(aSymbolOrInteger);
+     }
+#ifdef SOCK_STREAM
+     else if (aSymbolOrInteger == @symbol(stream)) 
+        code = SOCK_STREAM;
+#endif
+#ifdef SOCK_DGRAM
+     if (aSymbolOrInteger == @symbol(datagram)) 
+        code = SOCK_DGRAM;
+#endif
+#ifdef SOCK_RAW
+     if (aSymbolOrInteger == @symbol(raw)) 
+        code = SOCK_RAW;
+#endif
+
+     if (code > 0)
+         typeCode = __MKSMALLINT(code);
+%}.
+
+    ^ typeCode.
+
+    "
+     self socketTypeCodeOf:#stream
+     self socketTypeCodeOf:#datagram
+     self socketTypeCodeOf:#raw
+    "
+!
+
+socketTypeSymbolOf:anInteger
+
+    |socketTypeSymbol|
+
+%{ /*NOCONTEXT*/            
+
+    if (__isSmallInteger(anInteger)) {
+        switch(__intVal(anInteger)) {
+#ifdef SOCK_STREAM
+        case SOCK_STREAM:
+            socketTypeSymbol = @symbol(stream);
+            break;
+#endif
+#ifdef SOCK_DGRAM
+        case SOCK_DGRAM:
+            socketTypeSymbol = @symbol(datagram);
+            break;
+#endif
+#ifdef SOCK_RAW
+        case SOCK_RAW:
+            socketTypeSymbol = @symbol(raw);
+            break;
+#endif
+        }
+    }
+%}.
+
+    ^ socketTypeSymbol.
+!
+
+supportedProtocolFamilies
+    "return a collection of supported protocol families.
+     This list specifies what the Socket class supports -
+     socket creation may still fail, if your system was built
+     without it."
+
+    |list|
+
+    list := OrderedCollection new.
+
+%{
+#ifdef AF_INET
+%}.
+    list add:#inet.
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_UNIX
+%}.
+    list add:#unix.
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_INET6
+%}.
+    list add:#inet6.   "/ internet v6
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_APPLETALK
+%}.
+    list add:#appletalk.  "/ appletalk
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_DECnet
+%}.
+    list add:#decnet.  "/ dec net
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_NS
+%}.
+    list add:#xns.     "/ Xerox XNS
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_X25
+%}.
+    list add:#x25.     "/ X.25
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_SNA
+%}.
+    list add:#sna.     "/ IBM SNA
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_RAW
+%}.
+    list add:#raw.     "/ ?? RAW packets
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_ISO
+%}.
+    list add:#iso.     "/ ??
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_NETBIOS
+%}.
+    list add:#netbios. "/ ??
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_IPX
+%}.
+    list add:#ipx.     "/ Novell IPX
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_AX25
+%}.
+    list add:#ax25.    "/ Amateur Radio AX.25
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_NETROM
+%}.
+    list add:#netrom.  "/ Amateur Radio NET/ROM
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_BRIDGE
+%}.
+    list add:#bridge.  "/ multiprotocol bridge
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_BSC
+%}.
+    list add:#bsc.     "/ BISYNC 2780/3780
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_ROSE
+%}.
+    list add:#rose.    "/ Amateur Radio X.25 PLP
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_IRDA
+%}.
+    list add:#irda.  "/ infrared
+%{
+#endif
+%}.
+
+
+    ^ list
+
+    "
+     self supportedProtocolFamilies
+    "
+! !
+
+!UnixOperatingSystem::SocketHandle class methodsFor:'initialization'!
+
+reinitialize
+    "clear the protocol cache, when the system has been restarted"
+
+    ProtocolCache := nil.
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'accepting'!
+
+acceptWithPeerAddressBuffer:peerOrNil
+    "accept a connection on a server port.
+     Returns a new SocketHandle or nil if the operation
+     would block.
+     If peerOrNil is set to a ByteArray, the socket address
+     of the connection peer is stored into it."
+
+    |error newFd|
+
+%{
+#ifndef NO_SOCKET
+    int sock, newSock;
+    struct sockaddr *sap;
+    int alen;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (peerOrNil != nil && 
+        (!__isNonNilObject(peerOrNil) ||
+         (__intVal(__ClassInstPtr(__qClass(peerOrNil))->c_flags) & ARRAYMASK) != BYTEARRAY)) {
+        error = @symbol(badArgument2);
+        goto err;
+    }
+
+    sock = __smallIntegerVal(__INST(fd));
+
+again:
+    if (peerOrNil == nil) {
+        alen = 0;
+        sap = 0;
+    } else {
+        alen =  __byteArraySize(peerOrNil);
+        sap = (struct sockaddr *)__byteArrayVal(peerOrNil);
+    }
+    newSock = accept(sock, sap, &alen);
+    if (newSock < 0) {
+        switch (errno) {
+        case EINTR:
+            __HANDLE_INTERRUPTS__;
+            goto again;
+
+#ifdef EWOULDBLOCK
+        case EWOULDBLOCK:
+#else
+#if defined(EAGAIN)
+        case EAGAIN:
+#endif
+#endif
+            RETURN(nil);
+
+        default:
+            error = __mkSmallInteger(errno);
+            goto err;
+        }
+    }
+    newFd = __mkSmallInteger(newSock);
+
+err:;
+#endif /* not NO_SOCKET */
+%}.
+    error notNil ifTrue:[
+        self error:error.
+    ] ifFalse:[
+        ^ self class for:newFd
+    ]
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'binding'!
+
+bindTo:socketAddress
+    "low level bind - 
+     Set the local address of the socket"
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    int sock;
+    int sockaddr_size;
+    int ret;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__isNonNilObject(socketAddress) ||
+        (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+        error = @symbol(badArgument1);
+        goto err;
+    }
+    sockaddr_size = __byteArraySize(socketAddress);
+    sock = __INST(fd);
+
+again:
+    ret = bind(sock, (struct sockaddr *)__byteArrayVal(socketAddress), sockaddr_size);
+    if (ret < 0) {
+        if (errno == EINTR) {
+            __HANDLE_INTERRUPTS__;
+            goto again;
+        } else {
+            error = __mkSmallInteger(errno);
+            goto err;
+        }
+    }
+
+    err:;
+#endif /* NO_SOCKET */
+%}.
+    error notNil ifTrue:[
+        self error:error.
+    ].
+
+    "
+     (Socket domain:#inet type:#stream)
+         bindTo:(IPSocketAddress hostAddress:IPSocketAddress anyAddress port:9999)
+         reuseAddress:false ;
+     yourself
+    "
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'connecting'!
+
+cancelConnect
+    "cancel an asynchronous connect in progress"
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    int sock;
+    int ret;
+    struct sockaddr sockaddr = { AF_UNSPEC };
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    sock = __smallIntegerVal(__INST(fd));
+
+    /* 
+     * (dis-) connect by connecting to AF_UNSPEC socket 
+     */
+again:
+    ret = connect(sock, &sockaddr, sizeof(sockaddr));
+    if (ret < 0) {
+       switch(errno) {
+       case EINTR:
+# ifdef EAGAIN
+       case EAGAIN:
+# endif
+            __HANDLE_INTERRUPTS__;
+            goto again;
+
+        default:
+            error = __MKSMALLINT(errno);
+            break;
+        }
+    }
+
+err:;
+#endif /* NO_SOCKET */
+%}.
+!
+
+connectTo:socketAddress 
+    "low level connect; connect to a socket address.
+     Return true if connection has been established,
+     false, when the connection has been initiated but not yet
+     completed. If an error occured, an OSError is raised"
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    int sock;
+    int ret;
+    int sockaddr_size;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__isNonNilObject(socketAddress) ||
+        (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+        error = @symbol(badArgument1);
+        goto err;
+    }
+    sock = __smallIntegerVal(__INST(fd));
+    sockaddr_size = __qSize(socketAddress);
+
+again:
+    ret = connect(sock, (struct sockaddr *)__byteArrayVal(socketAddress), sockaddr_size);
+    if (ret >= 0) {
+        RETURN(true)
+    }
+
+    switch(errno) {
+    case EINTR:
+# ifdef EAGAIN
+    case EAGAIN:
+# endif
+        __HANDLE_INTERRUPTS__;
+        goto again;
+
+#if defined(EINPROGRESS) || defined(EALREADY)
+# ifdef EINPROGRESS
+    case EINPROGRESS: 
+# endif
+# ifdef EALREADY
+    case EALREADY:
+# endif
+        RETURN(false);
+#endif
+
+    default:
+        error = __MKSMALLINT(errno);
+        break;
+    }
+
+err:;
+#endif /* NO_SOCKET */
+%}.
+    error notNil ifTrue:[
+        self error:error.
+        ^ self
+    ].
+
+    "
+     Socket newTCP connectTo:(IPSocketAddress hostAddress:IPSocketAddress local port:7)
+                   withTimeout:nil.
+     Socket newTCP connectTo:(IPSocketAddress hostAddress:IPSocketAddress local port:5768)
+                   withTimeout:nil.
+     Socket newTCP connectTo:(IPSocketAddress hostAddress:#[1 2 3 4] port:7)
+                   withTimeout:nil.
+    "
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'datagram transmission'!
+
+receiveFrom:socketAddress buffer:aDataBuffer start:startIndex for:nBytes flags:flags 
+    "receive datagramm data - put address of originating host into
+     anAddressBuffer, data into aBuffer. For ST-80 compatibility,
+     the addressBuffer may be a non-ByteArray; then, it must understand
+     the addressBytes-message (i.e. be a SocketAddress instance).
+     Return the number of bytes received, or a negative number on error.
+
+     The thread blocks until data arrives - you may want to wait before
+     receiving, using #readWait or #readWaitWithTimeout:."
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    OBJ oClass;
+    int nInstVars, nInstBytes, objSize;
+    int sock;
+    struct sockaddr *saPtr;
+    int alen0, alen;
+    int n;
+    char *cp;
+    int __flags, __startIndex, __nBytes;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__isSmallInteger(startIndex) ||
+        (__startIndex = __intVal(startIndex)-1) < 0) {
+        if (startIndex == nil) {
+            __startIndex = 0;
+        } else {
+            error = @symbol(badArgument3);
+            goto err;
+        }
+    }
+    if (__isSmallInteger(nBytes)) {
+        __nBytes = __intVal(nBytes);
+    } else if (nBytes == nil) {
+        __nBytes = -1;
+    } else {
+        error = @symbol(badArgument4);
+        goto err;
+    }
+    if (!__isInteger(flags)) {
+        error = @symbol(badArgument5);
+        goto err;
+    }
+    __flags = __longIntVal(flags);
+    sock = __smallIntegerVal(__INST(fd));
+
+    oClass = __Class(aDataBuffer);
+    switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
+        case BYTEARRAY:
+        case WORDARRAY:
+        case SWORDARRAY:
+        case LONGARRAY:
+        case SLONGARRAY:
+        case FLOATARRAY:
+        case DOUBLEARRAY:
+            break;
+        default:
+            error = @symbol(badArgument2);
+            goto err;
+    }
+
+    nInstVars = __intVal(_ClassInstPtr(oClass)->c_ninstvars);
+    nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
+    objSize = __qSize(aDataBuffer) - nInstBytes;
+    nInstBytes += __startIndex;
+    objSize -= __startIndex;
+
+    if (__nBytes >= 0 &&__nBytes < objSize) {
+        objSize = __nBytes;
+    }
+
+    if (socketAddress == nil) {
+        alen0 = 0;
+    } else {
+        if (!__isNonNilObject(socketAddress) ||
+            (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+            error = @symbol(badArgument1);
+            goto err;
+        }
+        alen0 = __byteArraySize(socketAddress);
+    }
+    saPtr = (struct sockaddr *)0;
+
+again:
+    alen = alen0;
+    if (alen)
+        saPtr = (struct sockaddr *)__byteArrayVal(socketAddress);
+    cp = (char *)__InstPtr(aDataBuffer) + nInstBytes;
+    n = recvfrom(sock, cp, objSize, __flags, saPtr, &alen);
+    if (n < 0) {
+        if (errno == EINTR) {
+            __HANDLE_INTERRUPTS__;
+            goto again;
+        } else {
+            error = __MKSMALLINT(errno);
+            goto err;
+        }
+    }
+    RETURN (__mkSmallInteger(n));
+#endif
+err: ;
+%}.
+    self error:error.
+    ^ -1
+!
+
+sendTo:socketAddress buffer:aDataBuffer start:startIndex for:maxBytes flags:flags 
+    "send datagramm data - fetch address of destination host from
+     anAddressBuffer, data from aDataBuffer starting at startIndex,
+     sending count bytes.
+     SocketAddress must be an instance of SocketAddress
+     Return the number of bytes transmitted, or a negative number on error."
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    OBJ oClass;
+    int nInstVars, nInstBytes, objSize;
+    int sock;
+    int alen, n;
+    struct sockaddr *saPtr;
+    char *cp;
+    int __flags;
+    int offs, __startIndex, __maxBytes;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__isSmallInteger(startIndex) ||
+        (__startIndex = __intVal(startIndex)-1) < 0) {
+        if (startIndex == nil) {
+            __startIndex = 0;
+        } else {
+            error = @symbol(badArgument3);
+            goto err;
+        }
+    }
+    if (__isSmallInteger(maxBytes)) {
+        __maxBytes = __intVal(maxBytes);
+    } else if (maxBytes == nil) {
+        __maxBytes = -1;
+    } else {
+        error = @symbol(badArgument4);
+        goto err;
+    }
+    if (!__isInteger(flags)) {
+        error = @symbol(badArgument5);
+        goto err;
+    }
+    __flags = __longIntVal(flags);
+    sock = __smallIntegerVal(__INST(fd));
+
+    oClass = __Class(aDataBuffer);
+    switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
+        case BYTEARRAY:
+            offs = __startIndex;
+            break;
+        case WORDARRAY:
+        case SWORDARRAY:
+            offs = __startIndex * 2;
+            break;
+        case LONGARRAY:
+        case SLONGARRAY:
+            offs = __startIndex * 4;
+            break;
+        case LONGLONGARRAY:
+        case SLONGLONGARRAY:
+            offs = __startIndex * 8;
+# ifdef __NEED_LONGLONG_ALIGN
+            offs += 4;
+# endif
+        case FLOATARRAY:
+            offs = __startIndex * sizeof(float);
+            break;
+        case DOUBLEARRAY:
+            offs = __startIndex * sizeof(double);
+# ifdef __NEED_DOUBLE_ALIGN
+            offs += 4;
+# endif
+            break;
+        default:
+            error = @symbol(badArgument2);
+            goto err;
+    }
+
+    nInstVars = __smallIntegerVal(_ClassInstPtr(oClass)->c_ninstvars);
+    nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
+    objSize = __qSize(aDataBuffer) - nInstBytes - offs;
+
+    if (__maxBytes >= 0 && __maxBytes < objSize) {
+# ifdef DGRAM_DEBUG
+        printf("cut off ...\n");
+# endif
+        objSize = __maxBytes;
+    }
+
+    if (socketAddress == nil) {
+        alen = 0;
+    } else {
+        if (! __isByteArray(socketAddress)) {
+            error = @symbol(badArgument1);
+            goto err;
+        }
+        alen = __byteArraySize(socketAddress);
+    }
+    saPtr = (struct sockaddr *)0;
+
+again:
+    if (alen)
+        saPtr = (struct sockaddr *)__byteArrayVal(socketAddress);
+    cp = (char *)__InstPtr(aDataBuffer) + nInstBytes + offs;
+    n = sendto(sock, cp, objSize, __flags, saPtr, alen);
+    if (n < 0) {
+        if (errno == EINTR) {
+            __HANDLE_INTERRUPTS__;
+            goto again;
+        } else {
+            error = __MKSMALLINT(errno);
+            goto err;
+        }
+    }
+    RETURN (__mkSmallInteger(n));
+#endif
+err: ;
+%}.
+    self error:error.
+    ^ -1
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'initializing'!
+
+domain:domainArg type:typeArg protocol:protocolArg 
+    "set up socket with domain, type and protocol number.
+     This is a low level entry; no binding, listening or connect
+     is done. Both arguments must be symbols from one of
+     #inet,#unix, #appletalk, #x25 .. and #stream, #datagram, #raw resp."
+
+    |error domainCode protocolNumber|
+
+    domainCode := self class domainCodeOf:domainArg.
+    protocolArg notNil ifTrue:[
+        protocolNumber := self class protocolCodeOf:protocolArg
+    ].
+
+%{
+#ifndef NO_SOCKET
+    int dom, typ, proto = 0, sock, ret;
+    int on = 1;
+
+    if (__INST(fd) != nil) {
+        error = @symbol(internalError);
+        goto err;
+    }
+    if (! __isSmallInteger(domainCode)) { 
+        error = @symbol(badArgument1);
+        goto err;
+    }
+    if (! __isSymbol(typeArg)) { 
+        error = @symbol(badArgument2);
+        goto err;
+    }
+    if (protocolNumber != nil) {
+        if (!__isSmallInteger(protocolNumber)) {
+            error = @symbol(badArgument3);
+            goto err;
+        }
+        proto = __smallIntegerVal(protocolNumber);
+    }
+    dom = __smallIntegerVal(domainCode);    
+
+    /*
+     * get socket-type and protocol-type
+     */
+
+#ifdef SOCK_STREAM
+    if (typeArg == @symbol(stream)) {
+        typ = SOCK_STREAM;
+    } else
+#endif
+#ifdef SOCK_DGRAM
+    if (typeArg == @symbol(datagram)) {
+        typ = SOCK_DGRAM;
+    } else 
+#endif
+#ifdef SOCK_RAW
+    if (typeArg == @symbol(raw))
+        typ = SOCK_RAW;
+    else
+#endif
+#ifdef SOCK_SEQPACKET
+    if (typeArg == @symbol(seqPacket))
+        typ = SOCK_SEQPACKET;
+    else
+#endif
+    {
+        error = @symbol(badArgument2);
+        goto err;
+    }
+
+againSocket:
+    sock = socket(dom, typ, proto);
+    if (sock < 0) {
+        if (errno == EINTR) {
+            __HANDLE_INTERRUPTS__;
+            goto againSocket;
+        } else 
+#if defined(EPROTONOSUPPORT) /* for SGI */
+        if (errno == EPROTONOSUPPORT && proto != 0) {
+            proto = 0;
+            goto againSocket;
+        } else
+#endif
+        {
+            error = __mkSmallInteger(errno);
+            goto err;
+        }
+    }
+    __INST(fd) = __mkSmallInteger(sock);
+
+err:;
+#else
+    error := @symbol(notImplemented);
+#endif
+%}.
+    error notNil ifTrue:[
+        ^ self error:error.
+    ].
+    self register.
+
+    "
+     self new domain:#inet type:#stream protocol:nil
+    "
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'misc'!
+
+getOptionsLevel:level name:name 
+    "answer a ByteArray containing the socket option value 
+     named name at level"
+
+    |error bytes size|
+
+    bytes := ByteArray new:256.
+
+%{
+#ifndef NO_SOCKET
+    int sock;
+    int intval, sz;
+    char *p;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__bothSmallInteger(level, name)) {
+        error = @symbol(badArgument);
+        goto err;
+    }
+    if (!__isByteArray(bytes)) {
+        error = @symbol(internalError);
+        goto err;
+    }
+    p = __byteArrayVal(bytes);
+    sz = __byteArraySize(bytes);
+
+    sock = __smallIntegerVal(__INST(fd));
+    if (getsockopt(sock, __smallIntegerVal(level), __smallIntegerVal(name), p, &sz) < 0) {
+        error = __mkSmallInteger(errno);
+    }
+    size = __mkSmallInteger(sz);
+
+err:;
+#endif
+%}.
+    error notNil ifTrue:[
+        ^ self error:error
+    ].
+    ^ bytes copyTo:size
+!
+
+listenFor:aNumber 
+    "start listening.
+     aNumber is the number of connect indications queues
+     by the operating system"
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    int sock, ret;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__isSmallInteger(aNumber)) {
+        error = @symbol(badArgument1);
+        goto err;
+    }
+
+    sock = __smallIntegerVal(__INST(fd));
+
+again:
+    ret = listen(sock, __smallIntegerVal(aNumber));
+    if (ret < 0) {
+        if (errno == EINTR) {
+            __HANDLE_INTERRUPTS__;
+            goto again;
+        } else {
+            error = __mkSmallInteger(errno);
+        }
+    }
+
+err:;
+#endif
+%}.
+    error notNil ifTrue:[
+        self error:error.
+    ].
+!
+
+setOptionsLevel:level name:name value:value 
+    "set the socket option name at level to value.
+     Value ay be one of SmallInteger, ByteArray or nil"
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    int sock;
+    int intval, sz;
+    char *p;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__bothSmallInteger(level, name)) {
+        error = @symbol(badArgument);
+        goto err;
+    }
+    if (__isSmallInteger(value)) {
+        intval = __intVal(value);
+        p = (char *) &intval;
+        sz = sizeof(intval);
+    } else if (__isByteArray(value)) {
+        p = __byteArrayVal(value);
+        sz = __byteArraySize(value);
+    } else {
+        error = @symbol(badArgument3);
+        goto err;
+    }
+
+    sock = __smallIntegerVal(__INST(fd));
+    if (setsockopt(sock, __smallIntegerVal(level), __smallIntegerVal(name), p, sz) < 0) {
+        error = __mkSmallInteger(errno);
+    }
+err:;
+#endif
+%}.
+    error notNil ifTrue:[
+        ^ self error:error
+    ]
+!
+
+shutdown:anInteger 
+    "inform the socket that no more I/O will happen.
+     anInteger == 0   no reads will be performed
+     anInteger == 1   no writes will be performed
+     anInteger == 2   neither reads nor writes will be performed.
+                      Pending data is discarded. This is faster tha 
+                      close, which may wait until pending (written)
+                      data has been read by the other side"
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    int ret;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__isSmallInteger(anInteger)) {
+        error = @symbol(badArgument1);
+        goto err;
+    }
+
+again:
+    ret = shutdown(__smallIntegerVal(__INST(fd)), __smallIntegerVal(anInteger));
+    if (ret < 0) {
+        if (errno == EINTR) {
+            __HANDLE_INTERRUPTS__;
+            goto again;
+        } else {
+            error = __mkSmallInteger(errno);
+        }
+    }
+
+err:;
+#endif /*NO_SOCKET*/
+%}.
+    error notNil ifTrue:[
+        self error:error
+    ]
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'queries'!
+
+getNameInto:socketAddress
+    "answer the my own address (I am bound to this address).
+     Note that this address may change after connect or accept."
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    int sock;
+    int sockaddr_size;
+    int ret;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__isNonNilObject(socketAddress) ||
+        (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+        error = @symbol(badArgument1);
+        goto err;
+    }
+    sockaddr_size = __byteArraySize(socketAddress);
+
+    sock = __smallIntegerVal(__INST(fd));
+    ret = getsockname(sock, (struct sockaddr *)__byteArrayVal(socketAddress), &sockaddr_size);
+    if (ret < 0) {
+        error = __MKSMALLINT(errno);
+    }
+err:;
+#endif /* NO_SOCKET */
+%}.
+    error notNil ifTrue:[
+        ^ self error:error
+    ].
+    ^ socketAddress
+!
+
+getPeerInto:socketAddress
+    "answer the my own address (I am bound to this address).
+     Note that this address may change after connect or accept."
+
+    |error|
+
+%{
+#ifndef NO_SOCKET
+    int sock;
+    int sockaddr_size;
+    int ret;
+
+    if (!__isSmallInteger(__INST(fd))) {
+        error = @symbol(badFd);
+        goto err;
+    }
+    if (!__isNonNilObject(socketAddress) ||
+        (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+        error = @symbol(badArgument1);
+        goto err;
+    }
+    sockaddr_size = __byteArraySize(socketAddress);
+
+    sock = __smallIntegerVal(__INST(fd));
+    ret = getpeername(sock, (struct sockaddr *)__byteArrayVal(socketAddress), &sockaddr_size);
+    if (ret < 0) {
+        error = __mkSmallInteger(errno);
+    }
+err:;
+#endif /* NO_SOCKET */
+%}.
+    error notNil ifTrue:[
+        ^ self error:error
+    ].
+    ^ socketAddress
+! !
+
 !UnixOperatingSystem class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.107 2001-12-19 13:58:03 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.108 2001-12-21 16:42:00 stefan Exp $'
 ! !
 UnixOperatingSystem initialize!