Clean up:
authorStefan Vogel <sv@exept.de>
Fri, 28 Mar 2008 13:47:59 +0100
changeset 1935 326f8d31e7ca
parent 1934 fee89061a2e0
child 1936 d9cc04bdd113
Clean up: - inappropriate peer and port settings - method categories
Socket.st
--- a/Socket.st	Sat Mar 08 11:57:34 2008 +0100
+++ b/Socket.st	Fri Mar 28 13:47:59 2008 +0100
@@ -1517,7 +1517,7 @@
 
 listenOn:aPortNr backlogSize:aNumber
     self bindTo:aPortNr address:nil.
-    self listenWithBacklog:aNumber
+    self listenFor:aNumber
 
     "Created: / 31-05-2007 / 17:59:47 / cg"
 !
@@ -1530,7 +1530,7 @@
 !
 
 primSocketLocalPort:aSocket
-    ^ port
+    ^ self port
 !
 
 sendData: aStringOrByteArray
@@ -1588,6 +1588,305 @@
     "Created: / 04-06-2007 / 21:28:40 / cg"
 ! !
 
+!Socket methodsFor:'accepting connections'!
+
+accept
+    "create a new TCP socket from accepting on the receiver.
+     This method will suspend the current process if no connection is waiting.
+     For ST-80 compatibility"
+
+    |newSock|
+
+    self readWait.
+    newSock := self class new.
+    (newSock primAcceptOn:self blocking:false) ifFalse:[
+        "should raise an error here"
+        ^ nil
+    ].
+    ^ newSock
+
+    "
+     |sock newSock|
+
+     sock := Socket provide:8004.
+     sock listenFor:5.
+     newSock := sock accept.
+    "
+!
+
+blockingAccept
+    "create a new TCP socket from accepting on the receiver.
+     This method will suspend the smalltalk image with all smalltalk processes if no connection is waiting.
+     For ST-80 compatibility"
+
+    |newSock|
+
+    newSock := self class new.
+    (newSock primAcceptOn:self blocking:true) ifFalse:[
+        "should raise an error here"
+        ^ nil
+    ].
+    ^ newSock
+! !
+
+!Socket methodsFor:'binding'!
+
+bindAnonymously
+    "bind to any address. A free port will be allocated.
+     Our own socket address will be determined after conection set up.
+     This is the default after the socket has been created"
+
+    ^ self
+	bindTo:nil
+	address:nil
+	reuseAddress:false
+!
+
+bindAnonymouslyToAddress:addressString
+    "bind to address addressString.
+     A free port will be allocated"
+
+    ^ self
+	bindTo:nil
+	address:addressString
+	reuseAddress:false
+!
+
+bindTo:aSocketAddress
+    "ST80 compatible bind, expecting a socketAddress argument.
+     The socketAddress object (an instance of SocketAddress)
+     is supposed to respond to #portOrName and #address requests."
+
+    ^ self bindTo:(aSocketAddress portOrName)
+	   address:(aSocketAddress address)
+	   reuseAddress:true
+!
+
+bindTo:portNrOrNameString address:addressString
+    "low level bind - returns true if ok, false otherwise.
+     Currently only non-address binding is supported;
+     i.e. the address must always be nil.
+
+     The interpretation of portNrOrName depends on the domain:
+	inet domain uses (4byte) byteArray like internet numbers,
+	unix domain uses pathname strings,
+	others use whatever will come up in the future
+     "
+
+    ^ self
+	bindTo:portNrOrNameString
+	address:addressString
+	reuseAddress:true
+!
+
+bindTo:portNrOrNameOrNil address:hostOrPathNameOrSocketAddrOrNil reuseAddress:reuse
+    "low level bind - returns true if ok, false otherwise.
+     Currently only non-address binding is supported;
+     i.e. address must always be nil.
+
+     The interpretation of portNrOrName depends on the domain:
+        inet domain uses (4byte) byteArray like internet numbers,
+        unix domain uses pathname strings,
+        others use whatever will come up in the future
+
+     The reuse boolean argument controls if the SO_REUSEADDR socket option
+     is to be set (to avoid the 'bind: address in use' error).
+    "
+
+    |ok addr addrName domainClass error|
+
+    filePointer isNil ifTrue:[
+        ^ self errorNotOpen
+    ].
+
+    domainClass := self class socketAddressClassForDomain:domain.
+    domainClass isNil ifTrue:[
+        ^ self error:'invalid (unsupported) domain'.
+    ].
+
+    hostOrPathNameOrSocketAddrOrNil isNil ifTrue:[
+        addr := domainClass anyHost.
+    ] ifFalse:[
+        (hostOrPathNameOrSocketAddrOrNil isKindOf:SocketAddress) ifTrue:[
+            addr := hostOrPathNameOrSocketAddrOrNil.
+        ] ifFalse:[
+            "backward compatibility: support for byteArray and string arg"
+            hostOrPathNameOrSocketAddrOrNil isString ifTrue:[
+                addr := domainClass hostName:hostOrPathNameOrSocketAddrOrNil.
+                addrName := hostOrPathNameOrSocketAddrOrNil.
+            ] ifFalse:[
+                hostOrPathNameOrSocketAddrOrNil isByteArray ifFalse:[
+                    ^ self error:'bad host (socketAddress) argument'
+                ].
+                addr := domainClass hostAddress:hostOrPathNameOrSocketAddrOrNil.
+            ].
+        ].
+    ].
+    portNrOrNameOrNil notNil ifTrue:[
+        addr port:portNrOrNameOrNil.
+    ].
+    (portNrOrNameOrNil isNil or:[portNrOrNameOrNil == 0]) ifTrue:[
+        addr := addr copy.
+    ].
+
+%{  /* STACK: 100000 */
+#ifndef NO_SOCKET
+    OBJ fp = __INST(filePointer);
+
+    if (! __isBytes(addr)) {
+        error=__mkSmallInteger(-1);
+        addr = nil;
+        goto getOutOfHere;
+    }
+    if (fp != nil) {
+        SOCKET sock;
+        union sockaddr_u sa;
+        int sockaddr_size;
+        int ret;
+        int sockAddrOffs;
+
+        {
+            int nIndex;
+            OBJ cls;
+
+            sockAddrOffs = 0;
+            if ((cls = __qClass(addr)) != @global(ByteArray))
+                sockAddrOffs += __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
+            nIndex = __qSize(addr) - OHDR_SIZE;
+            sockaddr_size = nIndex - sockAddrOffs;
+            if (sockaddr_size > sizeof(sa)) {
+                error=__mkSmallInteger(-2);
+                goto getOutOfHere;
+            }
+            memcpy(&sa, __byteArrayVal(addr) + sockAddrOffs, sockaddr_size);
+        }
+
+        sock = SOCKET_FROM_FILE_OBJECT(fp);
+
+# ifdef SO_REUSEADDR
+        if (reuse == true) {
+            int on = 1;
+
+            if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
+                DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n"));
+            }
+        }
+# endif /* SO_REUSEADDR */
+
+# ifdef BIND_BLOCKS
+#  ifdef DO_WRAP_CALLS
+        do {
+            __threadErrno = 0;
+            ret = STX_WSA_CALL3("bind", bind, sock, &sa, sockaddr_size);
+        } while ((ret < 0) && (__threadErrno == EINTR));
+#  else
+        __BEGIN_INTERRUPTABLE__
+        do {
+            ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size);
+        } while ((ret < 0) && (errno == EINTR));
+        __END_INTERRUPTABLE__
+#  endif
+# else
+        ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size);
+# endif
+        if (ret < 0) {
+            DBGPRINTF(("SOCKET: bind failed errno=%d\n", errno));
+            error = __INST(lastErrorNumber) = __MKSMALLINT(errno);
+            goto getOutOfHere;
+        } else {
+            ok = true;
+
+            if (! __isSmallInteger(portNrOrNameOrNil)
+                || (portNrOrNameOrNil == __MKSMALLINT(0))) {
+                unsigned int alen = sockaddr_size;
+
+                /*
+                 * anonymous port - get the actual portNr
+                 */
+                if (getsockname(sock, (struct sockaddr *)&sa, &alen) < 0) {
+# ifdef WIN32
+                    errno = WSAGetLastError();
+# endif
+                    console_fprintf(stderr, "SOCKET: cannot get socketname: %d\n", errno);
+                }
+                memcpy(__byteArrayVal(addr) + sockAddrOffs, &sa, alen);
+            }
+        }
+    }
+#endif /* NO_SOCKET */
+
+getOutOfHere: ;
+%}.
+    ok ~~ true ifTrue:[
+        "maybe someone catches the error and binds to some other port..."
+        OpenError raiseRequestWith:self errorString:('cannot bind socket to port: <1p> address: <2p> (error=<3p>)' 
+                                                        expandMacrosWith:portNrOrNameOrNil 
+                                                        with:hostOrPathNameOrSocketAddrOrNil
+                                                        with:error).
+        ^ true.
+    ].
+
+    port := addr port.
+
+    ^ true
+
+    "
+     (Socket domain:#inet type:#stream)
+         bindTo:21
+         address:nil
+    "
+!
+
+listenFor:aNumber
+    "start listening; return true if ok, false on error
+     aNumber is the number of connect requests, that may be queued on the socket"
+
+    filePointer isNil ifTrue:[
+        ^ self errorNotOpen
+    ].
+%{
+#ifndef NO_SOCKET
+    OBJ fp = __INST(filePointer);
+    SOCKET sock;
+    int ret;
+
+    if (! __isSmallInteger(aNumber)) {
+        DBGPRINTF(("SOCKET: invalid arg\n"));
+        RETURN (false);
+    }
+
+    sock = SOCKET_FROM_FILE_OBJECT(fp);
+
+#ifdef LISTEN_BLOCKS
+# ifdef DO_WRAP_CALLS
+    do {
+        __threadErrno = 0;
+        ret = STX_WSA_CALL2("listen", listen, sock, __intVal(aNumber));
+    } while ((ret < 0) && (__threadErrno == EINTR));
+# else
+    __BEGIN_INTERRUPTABLE__
+    do {
+        ret = listen(sock, __intVal(aNumber));
+    } while ((ret < 0) && (errno == EINTR));
+    __END_INTERRUPTABLE__
+# endif
+#else
+    ret = listen(sock, __intVal(aNumber));
+#endif
+
+    if (ret < 0) {
+        DBGPRINTF(("SOCKET: listen call failed errno=%d\n", errno));
+        __INST(lastErrorNumber) = __MKSMALLINT(errno);
+        RETURN (false);
+    }
+#else
+    RETURN (false);
+#endif
+%}.
+    listening := true.
+    ^ true
+! !
+
 !Socket methodsFor:'closing'!
 
 shutDown
@@ -1615,6 +1914,208 @@
     self shutdown:1.
 ! !
 
+!Socket methodsFor:'connecting'!
+
+connectTo:hostOrPathName port:portNrOrName
+    "low level connect; connect to port, portNrOrNameOrNil on host, hostName.
+     For backward compatibility, host may be also a string or a byteArray,
+     but it is recommended to pass socketAddress instances.
+
+     Return true if ok, false otherwise.
+     The current process will block (but not the whole Smalltalk) until the connection is established.
+     See also: #connectTo:port:withTimeout: for a somewhat nicer interface."
+
+    ^ self connectTo:hostOrPathName port:portNrOrName withTimeout:nil
+!
+
+connectTo:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil withTimeout:timeout
+    "low level connect; connect to port, portNrOrNameOrNil on host, hostName.
+     For backward compatibility, host may be also a string or a byteArray,
+     but it is recommended to pass socketAddress instances.
+
+     Return true if ok, false otherwise.
+     The current process will block (but not the whole Smalltalk) until the connection is established,
+     or timeout millliseconds have passed."
+
+    |isAsync err domainClass addr addrName|
+
+    filePointer isNil ifTrue:[
+        ^ self errorNotOpen
+    ].
+
+    (hostOrPathNameOrSocketAddr isKindOf:SocketAddress) ifTrue:[
+        addr := hostOrPathNameOrSocketAddr.
+        portNrOrNameOrNil notNil ifTrue:[
+            addr port:portNrOrNameOrNil.
+        ].
+    ] ifFalse:[
+        "backward compatibility: support for byteArray and string arg"
+        domainClass := self class socketAddressClassForDomain:domain.
+        domainClass isNil ifTrue:[
+            ^ self error:'invalid (unsupported) domain'.
+        ].
+
+        hostOrPathNameOrSocketAddr isString ifTrue:[
+            addr := domainClass hostName:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil.
+            addrName := hostOrPathNameOrSocketAddr.
+        ] ifFalse:[
+            hostOrPathNameOrSocketAddr isByteCollection ifFalse:[
+                ^ self error:'bad host (socketAddress) argument'
+            ].
+            addr := domainClass hostAddress:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil.
+        ].
+    ].
+
+%{  /* STACK: 100000 */
+
+#ifndef NO_SOCKET
+    OBJ fp = __INST(filePointer);
+    union sockaddr_u sa;
+    SOCKET sock;
+    int a;
+    int ret, oldFlags;
+    int on = 1;
+    int sockaddr_size;
+
+    if (!__isNonNilObject(addr) || !__isBytes(addr)) {
+        DBGPRINTF(("SOCKET: invalid addrBytes\n"));
+        RETURN (false);
+    }
+
+    {
+        int sockAddrOffs, nIndex;
+        OBJ cls;
+
+        sockAddrOffs = 0;
+        if ((cls = __qClass(addr)) != @global(ByteArray))
+            sockAddrOffs += __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
+        nIndex = __qSize(addr) - OHDR_SIZE;
+        sockaddr_size = nIndex - sockAddrOffs;
+        if (sockaddr_size > sizeof(sa)) {
+            console_fprintf(stderr, "Socket: bad socketAddr\n");
+            RETURN (false);
+        }
+        bcopy((__byteArrayVal(addr) + sockAddrOffs), &sa, sockaddr_size);
+    }
+
+    sock = SOCKET_FROM_FILE_OBJECT(fp);
+
+# if defined(O_NONBLOCK)
+#  if !defined(WIN32)
+    /*
+     * set to non-blocking and wait later
+     */
+    oldFlags = fcntl(sock, F_GETFL, 0);
+    /* on SUNOS4.x, would use fcntl(osfd, F_SETFL, flags | FNDELAY); */
+    fcntl(sock, F_SETFL, oldFlags | O_NONBLOCK);
+#  endif
+# endif
+
+    /*
+     * connect
+     */
+# ifdef DO_WRAP_CALLS
+    do {
+        DBGFPRINTF((stderr, "SOCKET: connect...\n"));
+        __threadErrno = 0;
+        ret = STX_WSA_NOINT_CALL3("connect", connect, sock, &sa, sockaddr_size);
+        DBGFPRINTF((stderr, "SOCKET: connect(%d) -> %d (%d)\n", sock, ret, __threadErrno));
+    } while ((ret < 0) && (__threadErrno == EINTR));
+# else
+    __BEGIN_INTERRUPTABLE__
+    do {
+        ret = connect(sock, (struct sockaddr *)&sa, sockaddr_size);
+    } while ((ret < 0)
+             && ((errno == EINTR)
+# ifdef EAGAIN
+                 || (errno == EAGAIN)
+# endif
+                ));
+    __END_INTERRUPTABLE__
+#endif
+
+    if (ret < 0) {
+# if defined(EINPROGRESS) || defined(EALREADY)
+        if (0
+#  ifdef EINPROGRESS
+            || (errno == EINPROGRESS)
+#  endif
+#  ifdef EALREADY
+            || (errno == EALREADY)
+#  endif
+        ) {
+            /*
+             * This was a nonblocking operation that will take some time.
+             * Do a select on read to get informed when the operation is ready.
+             */
+            DBGFPRINTF((stderr, "SOCKET: isAsync is true\n"));
+            isAsync = true;
+        } else
+# endif /* EINPROGRESS or EALREADY */
+        {
+            DBGFPRINTF((stderr, "SOCKET: connect failed ret=%d errno=%d __threadErrno=%d\n",
+                        ret, errno, __threadErrno ));
+# ifdef DUMP_ADDRESS
+            {
+                char *cp = (char *)(&sa);
+                int i;
+
+                console_printf("address data:\n");
+                for (i=0; i<sockaddr_size; i++) {
+                    console_printf(" %02x\n", *cp++);
+                }
+            }
+# endif
+            __INST(lastErrorNumber) = __MKSMALLINT(errno);
+            RETURN (false);
+        }
+    }
+
+# if defined(O_NONBLOCK)
+#  if !defined(WIN32)
+    fcntl(sock, F_SETFL, oldFlags);
+#  endif
+# endif
+
+# else /* NO_SOCKET */
+    RETURN (false);
+# endif /* NO_SOCKET */
+%}.
+    isAsync == true ifTrue:[
+        (self writeWaitWithTimeoutMs:timeout) ifTrue:[
+            "/ a timeout occured
+            "/ should cancel the connect?
+            ^ false.
+        ].
+        err := self getSocketError.
+        err ~~ 0 ifTrue:[
+            lastErrorNumber := err.
+            ^ false.
+        ].
+    ].
+
+    peer := addr.
+    peerName := addrName.
+    port isNil ifTrue:[
+        "socket has not been explicitly bound,
+         after connect it has been bound implicitly - fetch the port"
+        port := self getFullSocketAddress port.
+    ].
+    ^ true
+
+    "
+       |sock|
+       sock := Socket newTCP.
+       sock connectTo:'localhost' port:21 withTimeout:1000.
+       sock
+
+       |sock|
+       sock := Socket newTCP.
+       sock connectTo:'localhost' port:9876 withTimeout:2000.
+       sock
+    "
+! !
+
 !Socket methodsFor:'datagram transmission'!
 
 receiveBuffer:aDataBuffer start:startIndex for:nBytes
@@ -2082,216 +2583,6 @@
     self primitiveFailed
 ! !
 
-!Socket methodsFor:'low level'!
-
-bindAnonymously
-    "bind to any address. A free port will be allocated.
-     Our own socket address will be determined after conection set up.
-     This is the default after the socket has been created"
-
-    ^ self
-	bindTo:nil
-	address:nil
-	reuseAddress:false
-!
-
-bindAnonymouslyToAddress:addressString
-    "bind to address addressString.
-     A free port will be allocated"
-
-    ^ self
-	bindTo:nil
-	address:addressString
-	reuseAddress:false
-!
-
-bindTo:aSocketAddress
-    "ST80 compatible bind, expecting a socketAddress argument.
-     The socketAddress object (an instance of SocketAddress)
-     is supposed to respond to #portOrName and #address requests."
-
-    ^ self bindTo:(aSocketAddress portOrName)
-	   address:(aSocketAddress address)
-	   reuseAddress:true
-!
-
-bindTo:portNrOrNameString address:addressString
-    "low level bind - returns true if ok, false otherwise.
-     Currently only non-address binding is supported;
-     i.e. the address must always be nil.
-
-     The interpretation of portNrOrName depends on the domain:
-	inet domain uses (4byte) byteArray like internet numbers,
-	unix domain uses pathname strings,
-	others use whatever will come up in the future
-     "
-
-    ^ self
-	bindTo:portNrOrNameString
-	address:addressString
-	reuseAddress:true
-!
-
-bindTo:portNrOrNameOrNil address:hostOrPathNameOrSocketAddrOrNil reuseAddress:reuse
-    "low level bind - returns true if ok, false otherwise.
-     Currently only non-address binding is supported;
-     i.e. address must always be nil.
-
-     The interpretation of portNrOrName depends on the domain:
-        inet domain uses (4byte) byteArray like internet numbers,
-        unix domain uses pathname strings,
-        others use whatever will come up in the future
-
-     The reuse boolean argument controls if the SO_REUSEADDR socket option
-     is to be set (to avoid the 'bind: address in use' error).
-    "
-
-    |ok addr addrName domainClass error|
-
-    filePointer isNil ifTrue:[
-        ^ self errorNotOpen
-    ].
-
-    domainClass := self class socketAddressClassForDomain:domain.
-    domainClass isNil ifTrue:[
-        ^ self error:'invalid (unsupported) domain'.
-    ].
-
-    hostOrPathNameOrSocketAddrOrNil isNil ifTrue:[
-        addr := domainClass anyHost.
-    ] ifFalse:[
-        (hostOrPathNameOrSocketAddrOrNil isKindOf:SocketAddress) ifTrue:[
-            addr := hostOrPathNameOrSocketAddrOrNil.
-        ] ifFalse:[
-            "backward compatibility: support for byteArray and string arg"
-            hostOrPathNameOrSocketAddrOrNil isString ifTrue:[
-                addr := domainClass hostName:hostOrPathNameOrSocketAddrOrNil.
-                addrName := hostOrPathNameOrSocketAddrOrNil.
-            ] ifFalse:[
-                hostOrPathNameOrSocketAddrOrNil isByteArray ifFalse:[
-                    ^ self error:'bad host (socketAddress) argument'
-                ].
-                addr := domainClass hostAddress:hostOrPathNameOrSocketAddrOrNil.
-            ].
-        ].
-    ].
-    portNrOrNameOrNil notNil ifTrue:[
-        addr port:portNrOrNameOrNil.
-    ].
-    (portNrOrNameOrNil isNil or:[portNrOrNameOrNil == 0]) ifTrue:[
-        addr := addr copy.
-    ].
-
-%{  /* STACK: 100000 */
-#ifndef NO_SOCKET
-    OBJ fp = __INST(filePointer);
-
-    if (! __isBytes(addr)) {
-        error=__mkSmallInteger(-1);
-        addr = nil;
-        goto getOutOfHere;
-    }
-    if (fp != nil) {
-        SOCKET sock;
-        union sockaddr_u sa;
-        int sockaddr_size;
-        int ret;
-        int sockAddrOffs;
-
-        {
-            int nIndex;
-            OBJ cls;
-
-            sockAddrOffs = 0;
-            if ((cls = __qClass(addr)) != @global(ByteArray))
-                sockAddrOffs += __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
-            nIndex = __qSize(addr) - OHDR_SIZE;
-            sockaddr_size = nIndex - sockAddrOffs;
-            if (sockaddr_size > sizeof(sa)) {
-                error=__mkSmallInteger(-2);
-                goto getOutOfHere;
-            }
-            memcpy(&sa, __byteArrayVal(addr) + sockAddrOffs, sockaddr_size);
-        }
-
-        sock = SOCKET_FROM_FILE_OBJECT(fp);
-
-# ifdef SO_REUSEADDR
-        if (reuse == true) {
-            int on = 1;
-
-            if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
-                DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n"));
-            }
-        }
-# endif /* SO_REUSEADDR */
-
-# ifdef BIND_BLOCKS
-#  ifdef DO_WRAP_CALLS
-        do {
-            __threadErrno = 0;
-            ret = STX_WSA_CALL3("bind", bind, sock, &sa, sockaddr_size);
-        } while ((ret < 0) && (__threadErrno == EINTR));
-#  else
-        __BEGIN_INTERRUPTABLE__
-        do {
-            ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size);
-        } while ((ret < 0) && (errno == EINTR));
-        __END_INTERRUPTABLE__
-#  endif
-# else
-        ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size);
-# endif
-        if (ret < 0) {
-            DBGPRINTF(("SOCKET: bind failed errno=%d\n", errno));
-            error = __INST(lastErrorNumber) = __MKSMALLINT(errno);
-            goto getOutOfHere;
-        } else {
-            ok = true;
-
-            if (! __isSmallInteger(portNrOrNameOrNil)
-                || (portNrOrNameOrNil == __MKSMALLINT(0))) {
-                unsigned int alen = sockaddr_size;
-
-                /*
-                 * anonymous port - get the actual portNr
-                 */
-                if (getsockname(sock, (struct sockaddr *)&sa, &alen) < 0) {
-# ifdef WIN32
-                    errno = WSAGetLastError();
-# endif
-                    console_fprintf(stderr, "SOCKET: cannot get socketname: %d\n", errno);
-                }
-                memcpy(__byteArrayVal(addr) + sockAddrOffs, &sa, alen);
-            }
-        }
-    }
-#endif /* NO_SOCKET */
-
-getOutOfHere: ;
-%}.
-    ok ~~ true ifTrue:[
-        "maybe someone catches the error and binds to some other port..."
-        OpenError raiseRequestWith:self errorString:('cannot bind socket to port: <1p> address: <2p> (error=<3p>)' 
-                                                        expandMacrosWith:portNrOrNameOrNil 
-                                                        with:hostOrPathNameOrSocketAddrOrNil
-                                                        with:error).
-        ^ true.
-    ].
-
-    peer := addr.
-    port := addr port.
-    peerName := addrName.
-
-    ^ true
-
-    "
-     (Socket domain:#inet type:#stream)
-         bindTo:21
-         address:nil
-    "
-! !
-
 !Socket protectedMethodsFor:'low level'!
 
 closeFile
@@ -2354,6 +2645,14 @@
 
 !Socket methodsFor:'low level'!
 
+getSocketAdress
+    "BAD SPELLING, of #getSocketAddress, kept for compatibility with swazoo"
+
+    <resource: #obsolete>
+
+    ^ self getSocketAddress
+!
+
 getSocketError
     "get the SO_ERROR form the socket, which indicates the
      result of an asynchronous operation"
@@ -2385,58 +2684,245 @@
 %}
 !
 
-listenFor:aNumber
-    "same as listenWithBacklog: - for ST-80 compatibility"
-
-    ^ self listenWithBacklog:aNumber
+listenWithBacklog:aNumber
+    <resource: #obsolete>
+    "same as listenFor: - backward compatibility with old ST/X"
+
+    ^ self listenFor:aNumber
 !
 
-listenWithBacklog:aNumber
-    "start listening; return true if ok, false on error"
-
-    filePointer isNil ifTrue:[
-	^ self errorNotOpen
+pollingWaitForNewConnectionOrDataOnAny:otherConnections timeout:timeoutSeconds
+    <resource: #obsolete>
+    "stupid MSDOS does not support select on sockets (sigh).
+     Must poll here."
+
+    |millis newConnection|
+
+    millis := timeoutSeconds * 1000.
+    [millis > 0] whileTrue:[
+	otherConnections size > 0 ifTrue:[
+	    otherConnections do:[:aConnection |
+		aConnection canReadWithoutBlocking ifTrue:[
+		    ^ aConnection
+		]
+	    ].
+	].
+	newConnection := self blockingAccept.
+	newConnection notNil ifTrue:[^ newConnection].
+	Delay waitForMilliseconds:20.
+	millis := millis - 20.
+    ].
+    ^ nil.
+!
+
+pollingWaitForNewConnectionWithTimeout:timeoutSeconds
+    <resource: #obsolete>
+    "stupid MSDOS does not support select on sockets (sigh).
+     Must poll here."
+
+    |millis newConnection|
+
+    timeoutSeconds notNil ifTrue:[
+	millis := timeoutSeconds * 1000.
+    ].
+    [millis isNil or:[millis > 0]] whileTrue:[
+	newConnection := self blockingAccept.
+	newConnection notNil ifTrue:[^ newConnection].
+	Delay waitForMilliseconds:20.
+	millis notNil ifTrue:[
+	    millis := millis - 20.
+	]
     ].
-%{
+    ^ nil.
+!
+
+primAcceptOn:aSocket blocking:blocking
+    "accept a connection on a server port (created with:'Socket>>onIPPort:')
+     usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)).
+     Return the true if ok; false if not.
+     If blocking is true, the accept() syscall (and the whole smalltalk image)
+     will block, until a connection is accepted.
+     If blocking is false, this call will return immediately, if there is no connection pending."
+
+    |serverSocketFd addr addrLen domainClass|
+
+    filePointer notNil ifTrue:[
+        ^ self errorAlreadyOpen
+    ].
+
+    domain := aSocket domain.
+    socketType := aSocket type.
+    serverSocketFd := aSocket fileDescriptor.
+    serverSocketFd isNil ifTrue:[
+        ^ self error:'invalid server socket'
+    ].
+    (serverSocketFd isMemberOf:SmallInteger) ifFalse:[
+        ^ self error:'invalid server socket'
+    ].
+
+    domainClass := self class socketAddressClassForDomain:domain.
+    domainClass isNil ifTrue:[
+        ^ self error:'invalid (unsupported) domain'.
+    ].
+    addrLen := domainClass socketAddressSize.
+    addr := domainClass new.
+
+%{  /* STACK: 100000 */
 #ifndef NO_SOCKET
-    OBJ fp = __INST(filePointer);
-    SOCKET sock;
-    int ret;
-
-    if (! __isSmallInteger(aNumber)) {
-	DBGPRINTF(("SOCKET: invalid arg\n"));
-	RETURN (false);
+    FILE *fp;
+    int flags;
+    SOCKET sock, newSock;
+    union sockaddr_u sa;
+    unsigned int alen, alen0;
+    struct hostent *he ;
+    char dotted[20] ;
+
+    if (!__isSmallInteger(addrLen)) {
+        DBGPRINTF(("SOCKET: bad addrLen\n"));
+        RETURN (false);
     }
-
-    sock = SOCKET_FROM_FILE_OBJECT(fp);
-
-#ifdef LISTEN_BLOCKS
+    alen0 = __intVal(addrLen);
+    sock = SOCKET_FROM_FD(__intVal(serverSocketFd));
+
+    if (blocking == false) {
+# if defined(O_NONBLOCK) && defined(SET_NDELAY)
+        flags = fcntl(sock, F_GETFL);
+        fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+# endif
+    }
+
 # ifdef DO_WRAP_CALLS
     do {
-	__threadErrno = 0;
-	ret = STX_WSA_CALL2("listen", listen, sock, __intVal(aNumber));
-    } while ((ret < 0) && (__threadErrno == EINTR));
+        __threadErrno = 0;
+        alen = alen0;
+        newSock = STX_WSA_CALL3("accept", accept, sock, &sa, &alen);
+    } while ((newSock < 0) && (__threadErrno == EINTR));
 # else
     __BEGIN_INTERRUPTABLE__
     do {
-	ret = listen(sock, __intVal(aNumber));
-    } while ((ret < 0) && (errno == EINTR));
+        alen = alen0;
+        newSock = accept(sock, (struct sockaddr *) &sa, &alen);
+    } while ((newSock < 0) && (errno == EINTR));
     __END_INTERRUPTABLE__
 # endif
-#else
-    ret = listen(sock, __intVal(aNumber));
-#endif
-
-    if (ret < 0) {
-	DBGPRINTF(("SOCKET: listen call failed errno=%d\n", errno));
-	__INST(lastErrorNumber) = __MKSMALLINT(errno);
-	RETURN (false);
+    DBGFPRINTF((stderr, "SOCKET: accept newSock=%d\n", newSock));
+
+    if (blocking == false) {
+# if defined(O_NDELAY) && defined(SET_NDELAY)
+        fcntl(sock, F_SETFL, flags);
+# endif
+    }
+
+    if (newSock < 0) {
+        DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno));
+        __INST(lastErrorNumber) = __MKSMALLINT(errno);
+        RETURN (false);
+    }
+
+    if (__isNonNilObject(addr)) {
+        OBJ oClass;
+        int nInstVars, nInstBytes, objSize;
+        char *cp;
+
+        oClass = __qClass(addr);
+        if (! __isBytes(addr) ) {
+            DBGPRINTF(("SOCKET: bad addr\n"));
+            closesocket(newSock);
+            RETURN (false);
+        }
+
+        nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
+        nInstBytes = OHDR_SIZE + (nInstVars * sizeof(OBJ));
+        objSize = __qSize(addr) - nInstBytes;
+        cp = (char *)__InstPtr(addr) + nInstBytes;
+        if (objSize < alen) {
+            DBGPRINTF(("SOCKET: bad addr\n"));
+            closesocket(newSock);
+            RETURN (false);
+        }
+
+        /*
+         * extract the partners address
+         */
+        bcopy((char *)&sa, cp, alen);
+        addrLen = __MKSMALLINT(alen);
+    }
+
+    /*
+     * make it a FILE *
+     */
+# ifdef WIN32
+    {
+        int _fd = _open_osfhandle(newSock, 0);
+        fp = fdopen(_fd, "r+");
+        DBGPRINTF(("SOCKET: sock=%d fd=%d fp=%x\n",newSock,_fd, fp));
     }
-#else
-    RETURN (false);
-#endif
+# else
+    fp = fdopen(newSock, "r+");
+# endif
+
+    if (! fp) {
+        DBGPRINTF(("SOCKET: fdopen call failed\n"));
+        __INST(lastErrorNumber) = __MKSMALLINT(errno);
+#  ifdef DO_WRAP_CALLS
+        {
+          int ret;
+          do {
+              __threadErrno = 0;
+              ret = STX_WSA_CALL1("closesocket", closesocket, newSock);
+          } while ((ret < 0) && (__threadErrno == EINTR));
+        }
+#  else
+        closesocket(newSock);
+#  endif
+        DBGFPRINTF((stderr, "SOCKET: close (fdopen failed) (%d)\n", newSock));
+        RETURN (false);
+    }
+
+    if ((@global(FileOpenTrace) == true) || __debugging__) {
+# ifdef WIN32
+        {
+            HANDLE h;
+            int _fd = fileno(fp);
+            h = (HANDLE)_get_osfhandle(_fd);
+            console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d) (H: %x)\n", fp, _fd, h);
+        }
+# else
+        console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d)\n", fp, newSock);
+# endif
+    }
+
+# ifdef BUGGY_STDIO_LIB
+    setbuf(fp, NULL);
+    __INST(buffered) = false;
+# endif
+
+# if 0
+    // The original code was:
+    __INST(filePointer) = __MKOBJ((INT)fp); __STORESELF(filePointer);
+    // but for that, gcc generates wrong code, which loads self (volatile) into
+    // a register (bp), then calls __MKOBJ, then stores indirect bp.
+    // That is wrong if a scavenge occurs in MKOBJ, as bp is now still pointing to the old
+    // object.
+# endif
+    {
+        OBJ t;
+
+        t = __MKOBJ(fp);
+        __INST(filePointer) = t;
+        __STORE(self, t);
+    }
+#endif /* not NO_SOCKET */
 %}.
-    listening := true.
+    mode := #readwrite.
+    Lobby register:self.
+    binary := false.
+    port := aSocket port.
+
+    addr notNil ifTrue:[
+        peer := addr.
+    ].
+
     ^ true
 ! !
 
@@ -2671,579 +3157,13 @@
 %}.
 ! !
 
-!Socket methodsFor:'low level-accepting'!
-
-accept
-    "create a new TCP socket from accepting on the receiver.
-     This method will suspend the current process if no connection is waiting.
-     For ST-80 compatibility"
-
-    |newSock|
-
-    newSock := self class new.
-    (newSock acceptOn:self) ifFalse:[^ nil].
-    ^ newSock
-
-    "
-     |sock newSock|
-
-     sock := Socket provide:8004.
-     sock listenFor:5.
-     newSock := sock accept.
-    "
-!
-
-acceptOn:aSocket
-    "accept a connection on a server port (created with:'Socket>>onIPPort:')
-     usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)).
-     This method will suspend the current process if no connection is waiting.
-     Return the true if ok; false if not."
-
-    aSocket readWait.
-    ^ self primAcceptOn:aSocket blocking:false.
-
-    "Modified: / 11.3.1996 / 14:21:31 / stefan"
-    "Modified: / 1.8.1998 / 23:39:10 / cg"
-!
-
-blockingAccept
-    "create a new TCP socket from accepting on the receiver.
-     This method will suspend the current process if no connection is waiting.
-     For ST-80 compatibility"
-
-    |newSock|
-
-    newSock := self class new.
-    (newSock blockingAcceptOn:self) ifFalse:[^ nil].
-    ^ newSock
-!
-
-blockingAcceptOn:aSocket
-    "accept a connection on a server port (created with:'Socket>>onIPPort:')
-     usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)).
-     This method will suspend the current process if no connection is waiting.
-     Return the true if ok; false if not."
-
-    ^ self primAcceptOn:aSocket blocking:true.
-!
-
-pollingWaitForNewConnectionOrDataOnAny:otherConnections timeout:timeoutSeconds
-    <resource: #obsolete>
-    "stupid MSDOS does not support select on sockets (sigh).
-     Must poll here."
-
-    |millis newConnection|
-
-    millis := timeoutSeconds * 1000.
-    [millis > 0] whileTrue:[
-	otherConnections size > 0 ifTrue:[
-	    otherConnections do:[:aConnection |
-		aConnection canReadWithoutBlocking ifTrue:[
-		    ^ aConnection
-		]
-	    ].
-	].
-	newConnection := self blockingAccept.
-	newConnection notNil ifTrue:[^ newConnection].
-	Delay waitForMilliseconds:20.
-	millis := millis - 20.
-    ].
-    ^ nil.
-!
-
-pollingWaitForNewConnectionWithTimeout:timeoutSeconds
-    <resource: #obsolete>
-    "stupid MSDOS does not support select on sockets (sigh).
-     Must poll here."
-
-    |millis newConnection|
-
-    timeoutSeconds notNil ifTrue:[
-	millis := timeoutSeconds * 1000.
-    ].
-    [millis isNil or:[millis > 0]] whileTrue:[
-	newConnection := self blockingAccept.
-	newConnection notNil ifTrue:[^ newConnection].
-	Delay waitForMilliseconds:20.
-	millis notNil ifTrue:[
-	    millis := millis - 20.
-	]
-    ].
-    ^ nil.
-!
-
-primAcceptOn:aSocket blocking:blocking
-    "accept a connection on a server port (created with:'Socket>>onIPPort:')
-     usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)).
-     Return the true if ok; false if not."
-
-    |serverSocketFd addr addrLen domainClass|
-
-    filePointer notNil ifTrue:[
-	^ self errorAlreadyOpen
-    ].
-
-    domain := aSocket domain.
-    socketType := aSocket type.
-    serverSocketFd := aSocket fileDescriptor.
-    serverSocketFd isNil ifTrue:[
-	^ self error:'invalid server socket'
-    ].
-    (serverSocketFd isMemberOf:SmallInteger) ifFalse:[
-	^ self error:'invalid server socket'
-    ].
-
-    domainClass := self class socketAddressClassForDomain:domain.
-    domainClass isNil ifTrue:[
-	^ self error:'invalid (unsupported) domain'.
-    ].
-    addrLen := domainClass socketAddressSize.
-    addr := domainClass new.
-
-%{  /* STACK: 100000 */
-#ifndef NO_SOCKET
-    FILE *fp;
-    int flags;
-    SOCKET sock, newSock;
-    union sockaddr_u sa;
-    unsigned int alen, alen0;
-    struct hostent *he ;
-    char dotted[20] ;
-
-    if (!__isSmallInteger(addrLen)) {
-	DBGPRINTF(("SOCKET: bad addrLen\n"));
-	RETURN (false);
-    }
-    alen0 = __intVal(addrLen);
-    sock = SOCKET_FROM_FD(__intVal(serverSocketFd));
-
-    if (blocking == false) {
-# if defined(O_NONBLOCK) && defined(SET_NDELAY)
-	flags = fcntl(sock, F_GETFL);
-	fcntl(sock, F_SETFL, flags | O_NONBLOCK);
-# endif
-    }
-
-# ifdef DO_WRAP_CALLS
-    do {
-	__threadErrno = 0;
-	alen = alen0;
-	newSock = STX_WSA_CALL3("accept", accept, sock, &sa, &alen);
-    } while ((newSock < 0) && (__threadErrno == EINTR));
-# else
-    __BEGIN_INTERRUPTABLE__
-    do {
-	alen = alen0;
-	newSock = accept(sock, (struct sockaddr *) &sa, &alen);
-    } while ((newSock < 0) && (errno == EINTR));
-    __END_INTERRUPTABLE__
-# endif
-    DBGFPRINTF((stderr, "SOCKET: accept newSock=%d\n", newSock));
-
-    if (blocking == false) {
-# if defined(O_NDELAY) && defined(SET_NDELAY)
-	fcntl(sock, F_SETFL, flags);
-# endif
-    }
-
-    if (newSock < 0) {
-	DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno));
-	__INST(lastErrorNumber) = __MKSMALLINT(errno);
-	RETURN (false);
-    }
-
-    if (__isNonNilObject(addr)) {
-	OBJ oClass;
-	int nInstVars, nInstBytes, objSize;
-	char *cp;
-
-	oClass = __qClass(addr);
-	if (! __isBytes(addr) ) {
-	    DBGPRINTF(("SOCKET: bad addr\n"));
-	    closesocket(newSock);
-	    RETURN (false);
-	}
-
-	nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
-	nInstBytes = OHDR_SIZE + (nInstVars * sizeof(OBJ));
-	objSize = __qSize(addr) - nInstBytes;
-	cp = (char *)__InstPtr(addr) + nInstBytes;
-	if (objSize < alen) {
-	    DBGPRINTF(("SOCKET: bad addr\n"));
-	    closesocket(newSock);
-	    RETURN (false);
-	}
-
-	/*
-	 * extract the partners address
-	 */
-	bcopy((char *)&sa, cp, alen);
-	addrLen = __MKSMALLINT(alen);
-    }
-
-    /*
-     * make it a FILE *
-     */
-# ifdef WIN32
-    {
-	int _fd = _open_osfhandle(newSock, 0);
-	fp = fdopen(_fd, "r+");
-	DBGPRINTF(("SOCKET: sock=%d fd=%d fp=%x\n",newSock,_fd, fp));
-    }
-# else
-    fp = fdopen(newSock, "r+");
-# endif
-
-    if (! fp) {
-	DBGPRINTF(("SOCKET: fdopen call failed\n"));
-	__INST(lastErrorNumber) = __MKSMALLINT(errno);
-#  ifdef DO_WRAP_CALLS
-	{
-	  int ret;
-	  do {
-	      __threadErrno = 0;
-	      ret = STX_WSA_CALL1("closesocket", closesocket, newSock);
-	  } while ((ret < 0) && (__threadErrno == EINTR));
-	}
-#  else
-	closesocket(newSock);
-#  endif
-	DBGFPRINTF((stderr, "SOCKET: close (fdopen failed) (%d)\n", newSock));
-	RETURN (false);
-    }
-
-    if ((@global(FileOpenTrace) == true) || __debugging__) {
-# ifdef WIN32
-	{
-	    HANDLE h;
-	    int _fd = fileno(fp);
-	    h = (HANDLE)_get_osfhandle(_fd);
-	    console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d) (H: %x)\n", fp, _fd, h);
-	}
-# else
-	console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d)\n", fp, newSock);
-# endif
-    }
-
-# ifdef BUGGY_STDIO_LIB
-    setbuf(fp, NULL);
-    __INST(buffered) = false;
-# endif
-
-# if 0
-    // The original code was:
-    __INST(filePointer) = __MKOBJ((INT)fp); __STORESELF(filePointer);
-    // but for that, gcc generates wrong code, which loads self (volatile) into
-    // a register (bp), then calls __MKOBJ, then stores indirect bp.
-    // That is wrong if a scavenge occurs in MKOBJ, as bp is now still pointing to the old
-    // object.
-# endif
-    {
-	OBJ t;
-
-	t = __MKOBJ(fp);
-	__INST(filePointer) = t;
-	__STORE(self, t);
-    }
-#endif /* not NO_SOCKET */
-%}.
-    mode := #readwrite.
-    Lobby register:self.
-    binary := false.
-    port := aSocket port.
-
-    addr notNil ifTrue:[
-	peer := addr.
-    ].
-
-    ^ true
-!
-
-waitForNewConnectionOrDataOnAny:otherConnections timeout:timeoutSeconds
-    "suspend the current process, until either a new connection comes
-     in at the receiver, or data arrives on any of the otherConnections.
-     For a new connection, an accept is performed and the new socket is returned.
-     For an old connection, that socket is returned.
-     In any case, the caller gets a socket to operate on as return value,
-     or nil, if a timeout occured.
-     This method implements the inner wait-primitive of a multi-connection
-     server application."
-
-
-    |wasBlocked sema|
-
-    "first, a quick check if data is already available"
-    self canReadWithoutBlocking ifTrue:[
-	^ self accept.
-    ].
-    otherConnections do:[:aConnection |
-	aConnection canReadWithoutBlocking ifTrue:[
-	    ^ aConnection
-	]
-    ].
-
-    [
-	"check again - prevent incoming interrupts from disturbing our setup"
-	wasBlocked := OperatingSystem blockInterrupts.
-
-	self canReadWithoutBlocking ifTrue:[
-	    ^ self accept.
-	].
-	otherConnections do:[:aConnection |
-	    aConnection canReadWithoutBlocking ifTrue:[
-		^ aConnection
-	    ]
-	].
-
-	"nope - must wait"
-	sema := Semaphore new name:'multiReadWait'.
-	otherConnections do:[:aConnection |
-	    Processor signal:sema onInput:(aConnection fileDescriptor).
-	].
-	Processor signal:sema onInput:(self fileDescriptor).
-	timeoutSeconds notNil ifTrue:[
-	    Processor signal:sema afterSeconds:timeoutSeconds
-	].
-	Processor activeProcess state:#ioWait.
-	sema wait.
-    ] ensure:[
-	sema notNil ifTrue:[Processor disableSemaphore:sema].
-	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
-    ].
-
-    "see who it was ..."
-    self canReadWithoutBlocking ifTrue:[
-	^ self accept.
-    ].
-    otherConnections do:[:aConnection |
-	aConnection canReadWithoutBlocking ifTrue:[
-	    ^ aConnection
-	]
-    ].
-
-    "none - a timeout"
-    ^ nil
-!
-
-waitForNewConnectionWithTimeout:timeoutSeconds
-    "suspend the current process, until a new connection comes
-     in at the receiver or a timeout occurs.
-     For a new connection, an accept is performed and the new socket is returned.
-     Returns nil, if a timeout occured.
-     This method implements the inner wait-primitive of a single-connection
-     server application."
-
-    (self readWaitWithTimeout:timeoutSeconds) ifTrue:[
-	"a timeout occurred - no connection within timeout"
-	^ nil
-    ].
-    ^ self accept.
-! !
-
-!Socket methodsFor:'low level-connecting'!
-
-connectTo:hostOrPathName port:portNrOrName
-    "low level connect; connect to port, portNrOrNameOrNil on host, hostName.
-     For backward compatibility, host may be also a string or a byteArray,
-     but it is recommended to pass socketAddress instances.
-
-     Return true if ok, false otherwise.
-     The current process will block (but not the whole Smalltalk) until the connection is established.
-     See also: #connectTo:port:withTimeout: for a somewhat nicer interface."
-
-    ^ self connectTo:hostOrPathName port:portNrOrName withTimeout:nil
-!
-
-connectTo:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil withTimeout:timeout
-    "low level connect; connect to port, portNrOrNameOrNil on host, hostName.
-     For backward compatibility, host may be also a string or a byteArray,
-     but it is recommended to pass socketAddress instances.
-
-     Return true if ok, false otherwise.
-     The current process will block (but not the whole Smalltalk) until the connection is established,
-     or timeout millliseconds have passed."
-
-    |isAsync err domainClass addr addrName|
-
-    filePointer isNil ifTrue:[
-        ^ self errorNotOpen
-    ].
-
-    (hostOrPathNameOrSocketAddr isKindOf:SocketAddress) ifTrue:[
-        addr := hostOrPathNameOrSocketAddr.
-        portNrOrNameOrNil notNil ifTrue:[
-            addr port:portNrOrNameOrNil.
-        ].
-    ] ifFalse:[
-        "backward compatibility: support for byteArray and string arg"
-        domainClass := self class socketAddressClassForDomain:domain.
-        domainClass isNil ifTrue:[
-            ^ self error:'invalid (unsupported) domain'.
-        ].
-
-        hostOrPathNameOrSocketAddr isString ifTrue:[
-            addr := domainClass hostName:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil.
-            addrName := hostOrPathNameOrSocketAddr.
-        ] ifFalse:[
-            hostOrPathNameOrSocketAddr isByteCollection ifFalse:[
-                ^ self error:'bad host (socketAddress) argument'
-            ].
-            addr := domainClass hostAddress:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil.
-        ].
-    ].
-
-%{  /* STACK: 100000 */
-
-#ifndef NO_SOCKET
-    OBJ fp = __INST(filePointer);
-    union sockaddr_u sa;
-    SOCKET sock;
-    int a;
-    int ret, oldFlags;
-    int on = 1;
-    int sockaddr_size;
-
-    if (!__isNonNilObject(addr) || !__isBytes(addr)) {
-        DBGPRINTF(("SOCKET: invalid addrBytes\n"));
-        RETURN (false);
-    }
-
-    {
-        int sockAddrOffs, nIndex;
-        OBJ cls;
-
-        sockAddrOffs = 0;
-        if ((cls = __qClass(addr)) != @global(ByteArray))
-            sockAddrOffs += __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
-        nIndex = __qSize(addr) - OHDR_SIZE;
-        sockaddr_size = nIndex - sockAddrOffs;
-        if (sockaddr_size > sizeof(sa)) {
-            console_fprintf(stderr, "Socket: bad socketAddr\n");
-            RETURN (false);
-        }
-        bcopy((__byteArrayVal(addr) + sockAddrOffs), &sa, sockaddr_size);
-    }
-
-    sock = SOCKET_FROM_FILE_OBJECT(fp);
-
-# if defined(O_NONBLOCK)
-#  if !defined(WIN32)
-    /*
-     * set to non-blocking and wait later
-     */
-    oldFlags = fcntl(sock, F_GETFL, 0);
-    /* on SUNOS4.x, would use fcntl(osfd, F_SETFL, flags | FNDELAY); */
-    fcntl(sock, F_SETFL, oldFlags | O_NONBLOCK);
-#  endif
-# endif
-
-    /*
-     * connect
-     */
-# ifdef DO_WRAP_CALLS
-    do {
-        DBGFPRINTF((stderr, "SOCKET: connect...\n"));
-        __threadErrno = 0;
-        ret = STX_WSA_NOINT_CALL3("connect", connect, sock, &sa, sockaddr_size);
-        DBGFPRINTF((stderr, "SOCKET: connect(%d) -> %d (%d)\n", sock, ret, __threadErrno));
-    } while ((ret < 0) && (__threadErrno == EINTR));
-# else
-    __BEGIN_INTERRUPTABLE__
-    do {
-        ret = connect(sock, (struct sockaddr *)&sa, sockaddr_size);
-    } while ((ret < 0)
-             && ((errno == EINTR)
-# ifdef EAGAIN
-                 || (errno == EAGAIN)
-# endif
-                ));
-    __END_INTERRUPTABLE__
-#endif
-
-    if (ret < 0) {
-# if defined(EINPROGRESS) || defined(EALREADY)
-        if (0
-#  ifdef EINPROGRESS
-            || (errno == EINPROGRESS)
-#  endif
-#  ifdef EALREADY
-            || (errno == EALREADY)
-#  endif
-        ) {
-            /*
-             * This was a nonblocking operation that will take some time.
-             * Do a select on read to get informed when the operation is ready.
-             */
-            DBGFPRINTF((stderr, "SOCKET: isAsync is true\n"));
-            isAsync = true;
-        } else
-# endif /* EINPROGRESS or EALREADY */
-        {
-            DBGFPRINTF((stderr, "SOCKET: connect failed ret=%d errno=%d __threadErrno=%d\n",
-                        ret, errno, __threadErrno ));
-# ifdef DUMP_ADDRESS
-            {
-                char *cp = (char *)(&sa);
-                int i;
-
-                console_printf("address data:\n");
-                for (i=0; i<sockaddr_size; i++) {
-                    console_printf(" %02x\n", *cp++);
-                }
-            }
-# endif
-            __INST(lastErrorNumber) = __MKSMALLINT(errno);
-            RETURN (false);
-        }
-    }
-
-# if defined(O_NONBLOCK)
-#  if !defined(WIN32)
-    fcntl(sock, F_SETFL, oldFlags);
-#  endif
-# endif
-
-# else /* NO_SOCKET */
-    RETURN (false);
-# endif /* NO_SOCKET */
-%}.
-    isAsync == true ifTrue:[
-        (self writeWaitWithTimeoutMs:timeout) ifTrue:[
-            "/ a timeout occured
-            "/ should cancel the connect?
-            ^ false.
-        ].
-        err := self getSocketError.
-        err ~~ 0 ifTrue:[
-            lastErrorNumber := err.
-            ^ false.
-        ].
-    ].
-    port := portNrOrNameOrNil.
-    peer := addr.
-    peerName := addrName.
-    ^ true
-
-    "
-       |sock|
-       sock := Socket newTCP.
-       sock connectTo:'localhost' port:21 withTimeout:1000.
-       sock
-
-       |sock|
-       sock := Socket newTCP.
-       sock connectTo:'localhost' port:9876 withTimeout:2000.
-       sock
-    "
-! !
-
 !Socket methodsFor:'printing & storing'!
 
 printOn:aStream
     aStream nextPutAll:self className; nextPutAll:'(protocol='.
     protocol printOn:aStream.
     aStream nextPutAll:' port='.
-    port printOn:aStream.
+    self port printOn:aStream.
     aStream nextPutAll:' peer='.
     peer printOn:aStream.
     aStream nextPut:$).
@@ -3258,19 +3178,19 @@
 !
 
 getFullSocketAddress
-    "implemented for swazoo project (primitive code cant be loaded as extension)
+    "implemented for swazoo project (primitive code can't be loaded as extension)
      Answer my own address (I am bound to this address).
      Note that this address may change after a connect or accept."
 
     |error domainClass addr addrLen|
 
     filePointer isNil ifTrue:[
-	^ self errorNotOpen
+        ^ self errorNotOpen
     ].
 
     domainClass := self class socketAddressClassForDomain:domain.
     domainClass isNil ifTrue:[
-	^ self error:'invalid (unsupported) domain'.
+        ^ self error:'invalid (unsupported) domain'.
     ].
     addrLen := domainClass socketAddressSize.
     addr := domainClass new.
@@ -3286,31 +3206,31 @@
     int addrObjSize, nAddrInstBytes;
 
     if (!__isSmallInteger(addrLen)) {
-	DBGPRINTF(("SOCKET: bad addrLen\n"));
-	error = @symbol(badArgument);
-	goto err;
+        DBGPRINTF(("SOCKET: bad addrLen\n"));
+        error = @symbol(badArgument);
+        goto err;
     }
     alen = alen0 = __intVal(addrLen);
 
     if (!__isNonNilObject(addr) || !__isBytes(addr)) {
-	DBGPRINTF(("SOCKET: bad addr\n"));
-	error = @symbol(badArgument);
-	goto err;
+        DBGPRINTF(("SOCKET: bad addr\n"));
+        error = @symbol(badArgument);
+        goto err;
     }
 
     {
-	OBJ addrClass;
-	int nAddrInstVars;
-
-	addrClass = __qClass(addr);
-	nAddrInstVars = __intVal(__ClassInstPtr(addrClass)->c_ninstvars);
-	nAddrInstBytes = OHDR_SIZE + (nAddrInstVars * sizeof(OBJ));
-	addrObjSize = __qSize(addr) - nAddrInstBytes;
-	if (addrObjSize < alen0) {
-	    DBGPRINTF(("SOCKET: bad addr/alen\n"));
-	    error = @symbol(badArgument);
-	    goto err;
-	}
+        OBJ addrClass;
+        int nAddrInstVars;
+
+        addrClass = __qClass(addr);
+        nAddrInstVars = __intVal(__ClassInstPtr(addrClass)->c_ninstvars);
+        nAddrInstBytes = OHDR_SIZE + (nAddrInstVars * sizeof(OBJ));
+        addrObjSize = __qSize(addr) - nAddrInstBytes;
+        if (addrObjSize < alen0) {
+            DBGPRINTF(("SOCKET: bad addr/alen\n"));
+            error = @symbol(badArgument);
+            goto err;
+        }
     }
 
     sock = SOCKET_FROM_FILE_OBJECT(fp);
@@ -3320,17 +3240,17 @@
     ret = getsockname(sock, (struct sockaddr *)&sa, &alen);
     if (ret < 0) {
 # ifdef WIN32
-	errno = WSAGetLastError();
+        errno = WSAGetLastError();
 # endif
-	DBGPRINTF(("SOCKET: getsocketname failed ret=%d errno=%d\n", ret, errno));
-	error = __MKSMALLINT(errno);
-	goto err;
+        DBGPRINTF(("SOCKET: getsocketname failed ret=%d errno=%d\n", ret, errno));
+        error = __MKSMALLINT(errno);
+        goto err;
     }
 
     if (addrObjSize < alen) {
-	DBGPRINTF(("SOCKET: bad addr\n"));
-	error = @symbol(badArgument);
-	goto err;
+        DBGPRINTF(("SOCKET: bad addr\n"));
+        error = @symbol(badArgument);
+        goto err;
     }
 
     addrP = (char *)__InstPtr(addr) + nAddrInstBytes;
@@ -3344,7 +3264,7 @@
 #endif /* NO_SOCKET */
 %}.
     error notNil ifTrue:[
-	^ self errorReporter reportOn:error
+        ^ self errorReporter reportOn:error
     ].
     ^ addr
 !
@@ -3352,7 +3272,7 @@
 getName
     "return the name; here, we return the ports name"
 
-    ^ port printString
+    ^ self port printString
 !
 
 getPeer
@@ -3360,9 +3280,6 @@
      my hostname/port combination.
      If you are interested in the hostname, use getPeerName directly."
 
-    peer isNil ifTrue:[
-	peer := self class peerFromDomain:domain name:peerName port:port.
-    ].
     ^ peer
 !
 
@@ -3382,15 +3299,6 @@
      Note that this address may change after connect or accept."
 
     ^ self getFullSocketAddress hostAddress
-    "/ ^ self getFullSocketAddress copyFrom:5 to:8
-!
-
-getSocketAdress
-    "BAD SPELLING, of #getSocketAddress, kept for compatibility with swazoo"
-
-    <resource: #obsolete>
-
-    ^ self getSocketAddress
 !
 
 isActive
@@ -3403,66 +3311,17 @@
     "return true, if the receiver has a connection"
 
     ^ self isActive
-      and:[port notNil
-      and:[peerName notNil or:[peer notNil]]]
-!
-
-old_getFullSocketAddress
-    "implemented for swazoo project primitive code cant load as extension
-     answer my own address (I am bound to this address).
-     Note that this address may change after connect or accept."
-
-    |socketAddress error|
-
-    filePointer isNil ifTrue:[
-	^ self errorNotOpen
-    ].
-    socketAddress := ByteArray new:16.
-
-%{
-#ifndef NO_SOCKET
-    OBJ fp = __INST(filePointer);
-    SOCKET sock;
-    unsigned int sockaddr_size;
-    int ret;
-
-    if (!__isNonNilObject(socketAddress) ||
-	(__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
-	error = @symbol(badArgument1);
-	goto err;
-    }
-    sockaddr_size = __byteArraySize(socketAddress);
-
-    sock = SOCKET_FROM_FILE_OBJECT(fp);
-    ret = getsockname(sock, (struct sockaddr *)__byteArrayVal(socketAddress), &sockaddr_size);
-    if (ret < 0) {
-# ifdef WIN32
-	errno = WSAGetLastError();
-# endif
-	DBGPRINTF(("SOCKET: getsocketname failed errno=%d\n", errno));
-	error = __MKSMALLINT(errno);
-    }
-err:;
-#else /* NO_SOCKET */
-    error = @symbol(notImplemented);
-#endif /* NO_SOCKET */
-%}.
-    error notNil ifTrue:[
-	^ self errorReporter reportOn:error
-    ].
-    ^ socketAddress
+        and:[peer notNil]
 !
 
 port
-    "return the port number (or name for unix-sockets) to which the socket is bound"
-
-"/ sometimes maybe we do am lazy fetch of the port
-"/    port == 0 ifTrue:[ |p|
-"/        p := self getPort.
-"/        p notNil ifTrue:[
-"/            port := p
-"/        ]
+    "return the port number (or name for unix-sockets) to which the socket is bound
+     - so this is the local port."
+
+"/    port isNil ifTrue:[
+"/        port := self getFullSocketAddress port.
 "/    ].
+
     ^ port
 !
 
@@ -3998,8 +3857,91 @@
     ^ false
 ! !
 
+!Socket methodsFor:'waiting'!
+
+waitForNewConnectionOrDataOnAny:otherConnections timeout:timeoutSeconds
+    "suspend the current process, until either a new connection comes
+     in at the receiver, or data arrives on any of the otherConnections.
+     For a new connection, an accept is performed and the new socket is returned.
+     For an old connection, that socket is returned.
+     In any case, the caller gets a socket to operate on as return value,
+     or nil, if a timeout occured.
+     This method implements the inner wait-primitive of a multi-connection
+     server application."
+
+
+    |wasBlocked sema|
+
+    "first, a quick check if data is already available"
+    self canReadWithoutBlocking ifTrue:[
+	^ self accept.
+    ].
+    otherConnections do:[:aConnection |
+	aConnection canReadWithoutBlocking ifTrue:[
+	    ^ aConnection
+	]
+    ].
+
+    [
+	"check again - prevent incoming interrupts from disturbing our setup"
+	wasBlocked := OperatingSystem blockInterrupts.
+
+	self canReadWithoutBlocking ifTrue:[
+	    ^ self accept.
+	].
+	otherConnections do:[:aConnection |
+	    aConnection canReadWithoutBlocking ifTrue:[
+		^ aConnection
+	    ]
+	].
+
+	"nope - must wait"
+	sema := Semaphore new name:'multiReadWait'.
+	otherConnections do:[:aConnection |
+	    Processor signal:sema onInput:(aConnection fileDescriptor).
+	].
+	Processor signal:sema onInput:(self fileDescriptor).
+	timeoutSeconds notNil ifTrue:[
+	    Processor signal:sema afterSeconds:timeoutSeconds
+	].
+	Processor activeProcess state:#ioWait.
+	sema wait.
+    ] ensure:[
+	sema notNil ifTrue:[Processor disableSemaphore:sema].
+	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+    ].
+
+    "see who it was ..."
+    self canReadWithoutBlocking ifTrue:[
+	^ self accept.
+    ].
+    otherConnections do:[:aConnection |
+	aConnection canReadWithoutBlocking ifTrue:[
+	    ^ aConnection
+	]
+    ].
+
+    "none - a timeout"
+    ^ nil
+!
+
+waitForNewConnectionWithTimeout:timeoutSeconds
+    "suspend the current process, until a new connection comes
+     in at the receiver or a timeout occurs.
+     For a new connection, an accept is performed and the new socket is returned.
+     Returns nil, if a timeout occured.
+     This method implements the inner wait-primitive of a single-connection
+     server application."
+
+    (self readWaitWithTimeout:timeoutSeconds) ifTrue:[
+	"a timeout occurred - no connection within timeout"
+	^ nil
+    ].
+    ^ self accept.
+! !
+
 !Socket class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.242 2007-11-08 14:04:43 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.243 2008-03-28 12:47:59 stefan Exp $'
 ! !