Socket.st
changeset 4568 c2b933093d63
parent 4506 9ea05177d1f7
child 4570 39e965ca8d06
--- a/Socket.st	Fri Jan 19 14:02:18 2018 +0100
+++ b/Socket.st	Fri Jan 19 14:49:15 2018 +0100
@@ -1670,10 +1670,12 @@
 
     newSock := self class new.
     (newSock primAcceptOn:self blocking:true) ifFalse:[
-	"should raise an error here"
-	^ nil
+        "should raise an error here - primitive code raises a notification"
+        ^ nil
     ].
     ^ newSock
+
+    "Modified (format): / 19-01-2018 / 13:32:25 / stefan"
 ! !
 
 !Socket methodsFor:'binding'!
@@ -1716,28 +1718,32 @@
 bindTo:portNrOrNameString address:addressString
     "Old interface: bind the socket to an address
      - returns true if ok, false otherwise.
+     Notify with a SocketErrorNotification on error.
 
      The interpretation of hostOrPathNameOrSocketAddrOrNil portNrOrName depends on the domain:
-	Best use a SocketAddress
-	For backward compatibility:
-	    AF_INET domain can also use (4byte) byteArray like internet numbers,
-	    AF_UNIX domain cab use pathname strings."
+        Best use a SocketAddress
+        For backward compatibility:
+            AF_INET domain can also use (4byte) byteArray like internet numbers,
+            AF_UNIX domain cab use pathname strings."
 
     ^ self
-	bindTo:portNrOrNameString
-	address:addressString
-	reuseAddress:true
+        bindTo:portNrOrNameString
+        address:addressString
+        reuseAddress:true
+
+    "Modified (comment): / 19-01-2018 / 13:36:54 / stefan"
 !
 
 bindTo:portNrOrNameOrNil address:hostOrPathNameOrSocketAddrOrNil reuseAddress:reuse
     "Old interface: bind the socket to an address
+     Notify with a SocketErrorNotification on error.
      - returns true if ok, false otherwise.
 
      The interpretation of hostOrPathNameOrSocketAddrOrNil portNrOrName depends on the domain:
-	Best use a SocketAddress
-	For backward compatibility:
-	    AF_INET domain can also use (4byte) byteArray like internet numbers,
-	    AF_UNIX domain can use pathname strings.
+        Best use a SocketAddress
+        For backward compatibility:
+            AF_INET domain can also use (4byte) byteArray like internet numbers,
+            AF_UNIX domain can use pathname strings.
 
      The reuse boolean argument controls if the SO_REUSEADDR socket option
      is to be set (to avoid the 'bind: address in use' error).
@@ -1746,40 +1752,43 @@
     |socketAddress|
 
     handle isNil ifTrue:[
-	^ self errorNotOpen
+        ^ self errorNotOpen
     ].
 
     hostOrPathNameOrSocketAddrOrNil isNil ifTrue:[
-	socketAddress := self socketAddressClass anyHost.
+        socketAddress := self socketAddressClass anyHost.
     ] ifFalse:[
-	(hostOrPathNameOrSocketAddrOrNil isSocketAddress) ifTrue:[
-	    socketAddress := hostOrPathNameOrSocketAddrOrNil.
-	] ifFalse:[
-	    "backward compatibility: support for byteArray and string arg"
-	    hostOrPathNameOrSocketAddrOrNil isString ifTrue:[
-		socketAddress := self socketAddressClass hostName:hostOrPathNameOrSocketAddrOrNil.
-	    ] ifFalse:[
-		hostOrPathNameOrSocketAddrOrNil isByteCollection ifFalse:[
-		    ^ self error:'bindTo: bad host (socketAddress) argument'
-		].
-		socketAddress := self socketAddressClass hostAddress:hostOrPathNameOrSocketAddrOrNil.
-	    ].
-	].
+        (hostOrPathNameOrSocketAddrOrNil isSocketAddress) ifTrue:[
+            socketAddress := hostOrPathNameOrSocketAddrOrNil.
+        ] ifFalse:[
+            "backward compatibility: support for byteArray and string arg"
+            hostOrPathNameOrSocketAddrOrNil isString ifTrue:[
+                socketAddress := self socketAddressClass hostName:hostOrPathNameOrSocketAddrOrNil.
+            ] ifFalse:[
+                hostOrPathNameOrSocketAddrOrNil isByteCollection ifFalse:[
+                    ^ self error:'bindTo: bad host (socketAddress) argument'
+                ].
+                socketAddress := self socketAddressClass hostAddress:hostOrPathNameOrSocketAddrOrNil.
+            ].
+        ].
     ].
     portNrOrNameOrNil notNil ifTrue:[
-	socketAddress port:portNrOrNameOrNil.
+        socketAddress port:portNrOrNameOrNil.
     ].
 
     ^ self bindTo:socketAddress reuseAddress:reuse.
 
     "
      (Socket domain:#'AF_INET' type:#stream)
-	 bindTo:2144 address:nil; yourself
+         bindTo:2144 address:nil; yourself
     "
+
+    "Modified (comment): / 19-01-2018 / 13:37:13 / stefan"
 !
 
 bindTo:aSocketAddress reuseAddress:reuse
     "Bind the socket to aSocketAddress - returns true if ok, false otherwise.
+     Notify with a SocketErrorNotification on error.
 
      The reuse boolean argument controls if the SO_REUSEADDR socket option
      is to be set (to avoid the 'bind: address in use' error).
@@ -1789,17 +1798,17 @@
     |ok error socketAddress|
 
     handle isNil ifTrue:[
-	^ self errorNotOpen
+        ^ self errorNotOpen
     ].
     socketAddress := aSocketAddress.
     socketAddress isNil ifTrue:[
-	"ok, get a all zero socket address, so it is for anyHost
-	 and the port will be assigned"
-	socketAddress := self socketAddressClass new.
+        "ok, get a all zero socket address, so it is for anyHost
+         and the port will be assigned"
+        socketAddress := self socketAddressClass new.
     ].
     domain == #'AF_INET6' ifTrue:[
-	"accept also IPv4 connections on IPv6 sockets (this is off by default for windows"
-	self setSocketOption:#'IPV6_V6ONLY' argument:false argument:nil.
+        "accept also IPv4 connections on IPv6 sockets (this is off by default for windows"
+        self setSocketOption:#'IPV6_V6ONLY' argument:false argument:nil.
     ].
     ok := false.
 
@@ -1813,52 +1822,52 @@
     int sockAddrOffs;
 
     if (fp == nil) {
-	goto getOutOfHere;
+        goto getOutOfHere;
     }
 
     if (! __isBytes(socketAddress)) {
-	error = __mkSmallInteger(-1);
-	goto getOutOfHere;
+        error = __mkSmallInteger(-1);
+        goto getOutOfHere;
     }
     /* get the socket-address */
     if (__isNonNilObject(socketAddress)){
-	int nIndex;
-	OBJ cls = __qClass(socketAddress);
-
-	sockAddrOffs = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
-	nIndex = __qSize(socketAddress) - OHDR_SIZE;
-	sockaddr_size = nIndex - sockAddrOffs;
-	if (sockaddr_size > sizeof(sa)) {
-	    error=__mkSmallInteger(-2);
-	    goto getOutOfHere;
-	}
-	memcpy(&sa, __byteArrayVal(socketAddress) + sockAddrOffs, sockaddr_size);
+        int nIndex;
+        OBJ cls = __qClass(socketAddress);
+
+        sockAddrOffs = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
+        nIndex = __qSize(socketAddress) - OHDR_SIZE;
+        sockaddr_size = nIndex - sockAddrOffs;
+        if (sockaddr_size > sizeof(sa)) {
+            error=__mkSmallInteger(-2);
+            goto getOutOfHere;
+        }
+        memcpy(&sa, __byteArrayVal(socketAddress) + 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"));
-	}
+        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_NOINT_CALL3("bind", bind, sock, &sa, sockaddr_size);
+        __threadErrno = 0;
+        ret = STX_WSA_NOINT_CALL3("bind", bind, sock, &sa, sockaddr_size);
     } while ((ret < 0) && (__threadErrno == EINTR));
     if (ret < 0) {
-	errno = __threadErrno;
+        errno = __threadErrno;
     }
 #  else
     __BEGIN_INTERRUPTABLE__
     do {
-	ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size);
+        ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size);
     } while ((ret < 0) && (errno == EINTR));
     __END_INTERRUPTABLE__
 #  endif
@@ -1868,77 +1877,82 @@
 # endif
     if (ret < 0) {
 # ifdef __win32__
-	if (errno == 0) {
-	    errno = WSAGetLastError();
-	}
+        if (errno == 0) {
+            errno = WSAGetLastError();
+        }
 # endif
-	DBGPRINTF(("SOCKET: bind failed errno=%d\n", errno));
-	error = __INST(lastErrorNumber) = __MKSMALLINT(errno);
-	goto getOutOfHere;
+        DBGPRINTF(("SOCKET: bind failed errno=%d\n", errno));
+        error = __INST(lastErrorNumber) = __MKSMALLINT(errno);
+        goto getOutOfHere;
     } else {
-	ok = true;
+        ok = true;
     }
 #endif /* NO_SOCKET */
 
 getOutOfHere: ;
 %}.
     ok ifFalse:[
-	|errorHolder errorString|
-
-	error isInteger ifTrue:[
-	    errorHolder := OperatingSystem errorHolderForNumber:error.
-	    errorString := errorHolder errorString.
-	] ifFalse:[
-	    errorString := error.
-	].
-	OpenError newException
-	    errorString:('cannot bind socket to address: %1 (%2)'
-			    bindWith:socketAddress
-			    with:errorString);
-	    errorCode:error;
-	    osErrorHolder:errorHolder;
-	    parameter:self;
-	    raiseRequest.
-	"maybe someone catches the error and binds to some other port..."
-	^ true.
+        |errorHolder errorString|
+
+        error isInteger ifTrue:[
+            errorHolder := OperatingSystem errorHolderForNumber:error.
+            errorString := errorHolder errorString.
+        ] ifFalse:[
+            errorString := error.
+        ].
+        OpenError newException
+            errorString:('cannot bind socket to address: %1 (%2)'
+                            bindWith:socketAddress
+                            with:errorString);
+            errorCode:error;
+            osErrorHolder:errorHolder;
+            parameter:self;
+            raiseRequest.
+        "maybe someone catches the error and binds to some other port..."
+        ^ true.
     ].
 
     port := socketAddress port.
     port == 0 ifTrue:[
-	"this is a bind to a random port, now we can get the real port"
-	port := self getFullSocketAddress port.
+        "this is a bind to a random port, now we can get the real port"
+        port := self getFullSocketAddress port.
     ].
     ^ true
 
     "
      (Socket domain:#'AF_INET' type:#stream)
-	bindTo:(IPSocketAddress anyHost port:445) reuseAddress:false;
-	yourself.
+        bindTo:(IPSocketAddress anyHost port:445) reuseAddress:false;
+        yourself.
 
      (Socket domain:#'AF_INET' type:#stream)
-	bindTo:139 reuseAddress:false;
-	yourself.
+        bindTo:139 reuseAddress:false;
+        yourself.
 
      (Socket domain:#'AF_INET6' type:#stream)
-	bindTo:nil reuseAddress:false;
-	yourself.
+        bindTo:nil reuseAddress:false;
+        yourself.
 
      (Socket domain:#'AF_INET' type:#stream)
-	bindTo:(IPSocketAddress localHost port:2122) reuseAddress:false;
-	yourself.
+        bindTo:(IPSocketAddress localHost port:2122) reuseAddress:false;
+        yourself.
 
      (Socket domain:#'AF_UNIX' type:#stream)
-	bindTo:nil reuseAddress:false;
-	yourself.
+        bindTo:nil reuseAddress:false;
+        yourself.
     "
+
+    "Modified: / 19-01-2018 / 13:37:21 / stefan"
 !
 
 listenFor:aNumber
-    "start listening; return true if ok, false on error
+    "start listening; return true if ok, false on error.
+     Notify with a SocketErrorNotification on error.
      aNumber is the number of connect requests, that may be queued on the socket"
 
+    |err|
+
     handle isNil ifTrue:[
-	^ self errorNotOpen
+        ^ self errorNotOpen
     ].
 %{
 #ifndef NO_SOCKET
@@ -1947,8 +1961,9 @@
     int ret;
 
     if (! __isSmallInteger(aNumber)) {
-	DBGPRINTF(("SOCKET: invalid arg\n"));
-	RETURN (false);
+        DBGPRINTF(("SOCKET: invalid arg\n"));
+        err = @symbol(badArgument);
+        goto out;
     }
 
     sock = SOCKET_FROM_FILE_OBJECT(fp);
@@ -1956,16 +1971,16 @@
 #ifdef LISTEN_BLOCKS
 # ifdef DO_WRAP_CALLS
     do {
-	__threadErrno = 0;
-	ret = STX_WSA_NOINT_CALL2("listen", listen, sock, __intVal(aNumber));
+        __threadErrno = 0;
+        ret = STX_WSA_NOINT_CALL2("listen", listen, sock, __intVal(aNumber));
     } while ((ret < 0) && (__threadErrno == EINTR));
     if (ret < 0) {
-	errno = __threadErrno;
+        errno = __threadErrno;
     }
 # else
     __BEGIN_INTERRUPTABLE__
     do {
-	ret = listen(sock, __intVal(aNumber));
+        ret = listen(sock, __intVal(aNumber));
     } while ((ret < 0) && (errno == EINTR));
     __END_INTERRUPTABLE__
 # endif
@@ -1976,20 +1991,41 @@
 
     if (ret < 0) {
 # ifdef __win32__
-	if (errno == 0) {
-	    errno = WSAGetLastError();
-	}
+        if (errno == 0) {
+            errno = WSAGetLastError();
+        }
 # endif
-	DBGPRINTF(("SOCKET: listen call failed errno=%d\n", errno));
-	__INST(lastErrorNumber) = __MKSMALLINT(errno);
-	RETURN (false);
+        err = __MKSMALLINT(errno);
+        DBGPRINTF(("SOCKET: listen call failed errno=%d\n", errno));
+        goto out;
     }
 #else
     RETURN (false);
 #endif
+out:;
 %}.
+    err notNil ifTrue:[
+        err isSymbol ifTrue:[
+            self error:err.
+        ].
+        ^ self reportError:err.
+    ].
+
     listening := aNumber.
     ^ true
+
+    "
+       [
+           |sock|
+           sock := Socket newTCP.
+           sock listenFor:1.
+           sock
+       ] on:SocketErrorNotification do:[:ex|
+           ex halt.
+       ].
+    "
+
+    "Modified (comment): / 19-01-2018 / 13:50:09 / stefan"
 ! !
 
 !Socket methodsFor:'closing'!
@@ -2059,32 +2095,34 @@
      but it is recommended to pass SocketAddress instances.
 
      Return true if ok, false otherwise.
+     Notify with a SocketErrorNotification on error.
+
      The current process will block (but not the whole Smalltalk) until the connection is established,
      or timeout milliseconds have passed."
 
     |domainClass socketAddress|
 
     (hostOrPathNameOrSocketAddr isSocketAddress) ifTrue:[
-	socketAddress := hostOrPathNameOrSocketAddr.
-	portNrOrNameOrNil notNil ifTrue:[
-	    socketAddress port:portNrOrNameOrNil.
-	].
+        socketAddress := hostOrPathNameOrSocketAddr.
+        portNrOrNameOrNil notNil ifTrue:[
+            socketAddress 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:[
-	    socketAddress := domainClass hostName:hostOrPathNameOrSocketAddr serviceName:portNrOrNameOrNil type:#SOCK_STREAM.
-	    peerName := hostOrPathNameOrSocketAddr.
-	] ifFalse:[
-	    hostOrPathNameOrSocketAddr isByteCollection ifFalse:[
-		^ self error:'connectTo: bad host (socketAddress) argument'
-	    ].
-	    socketAddress := domainClass hostAddress:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil.
-	].
+        "backward compatibility: support for byteArray and string arg"
+        domainClass := self class socketAddressClassForDomain:domain.
+        domainClass isNil ifTrue:[
+            ^ self error:'invalid (unsupported) domain'.
+        ].
+
+        hostOrPathNameOrSocketAddr isString ifTrue:[
+            socketAddress := domainClass hostName:hostOrPathNameOrSocketAddr serviceName:portNrOrNameOrNil type:#SOCK_STREAM.
+            peerName := hostOrPathNameOrSocketAddr.
+        ] ifFalse:[
+            hostOrPathNameOrSocketAddr isByteCollection ifFalse:[
+                ^ self error:'connectTo: bad host (socketAddress) argument'
+            ].
+            socketAddress := domainClass hostAddress:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil.
+        ].
     ].
 
     ^ self connectTo:socketAddress withTimeout:timeout.
@@ -2100,19 +2138,23 @@
        sock connectTo:'localhost' port:9876 withTimeout:2000.
        sock
     "
+
+    "Modified (comment): / 19-01-2018 / 13:38:10 / stefan"
 !
 
 connectTo:aSocketAddress withTimeout:timeout
     "Connect to a SocketAddress.
 
      Return true if ok, false otherwise.
+     Notify with a SocketErrorNotification on error.
+
      The current process will block (but not the whole Smalltalk) until the connection is established,
      or timeout milliseconds have passed."
 
     |isAsync err|
 
     handle isNil ifTrue:[
-	^ self errorNotOpen
+        ^ self errorNotOpen
     ].
     isAsync := false.
 
@@ -2133,25 +2175,25 @@
     int sockaddr_size;
 
     if (!__isNonNilObject(aSocketAddress) || !__isBytes(aSocketAddress)) {
-	DBGPRINTF(("SOCKET: invalid socketAddress\n"));
-	err = @symbol(argumentError);
-	goto out;
+        DBGPRINTF(("SOCKET: invalid socketAddress\n"));
+        err = @symbol(argumentError);
+        goto out;
     }
 
     {
-	int sockAddrOffs = 0;
-	int nIndex =__byteArraySize(aSocketAddress);
-	OBJ cls = __qClass(aSocketAddress);
-
-	//if (cls != @global(ByteArray))
-	//    sockAddrOffs = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
-	sockaddr_size = nIndex - sockAddrOffs;
-	if (sockaddr_size > sizeof(sa)) {
-	    DBGPRINTF(("SOCKET: invalid (short) socketAddress\n"));
-	    err = @symbol(argumentError);
-	    goto out;
-	}
-	memcpy(&sa, __byteArrayVal(aSocketAddress) + sockAddrOffs, sockaddr_size);
+        int sockAddrOffs = 0;
+        int nIndex =__byteArraySize(aSocketAddress);
+        OBJ cls = __qClass(aSocketAddress);
+
+        //if (cls != @global(ByteArray))
+        //    sockAddrOffs = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
+        sockaddr_size = nIndex - sockAddrOffs;
+        if (sockaddr_size > sizeof(sa)) {
+            DBGPRINTF(("SOCKET: invalid (short) socketAddress\n"));
+            err = @symbol(argumentError);
+            goto out;
+        }
+        memcpy(&sa, __byteArrayVal(aSocketAddress) + sockAddrOffs, sockaddr_size);
     }
 
     sock = SOCKET_FROM_FILE_OBJECT(fp);
@@ -2178,18 +2220,18 @@
 
 
     do {
-	DBGFPRINTF((stderr, "SOCKET: (sock=%d) connect...\n", sock));
-	ret = STX_WSA_NOINT_CALL3("connect", connect, sock, &sa, (INT)sockaddr_size);
-	DBGFPRINTF((stderr, "SOCKET: connect(%d) -> %"_ld_" (%d)\n", sock, (INT)ret, __threadErrno));
+        DBGFPRINTF((stderr, "SOCKET: (sock=%d) connect...\n", sock));
+        ret = STX_WSA_NOINT_CALL3("connect", connect, sock, &sa, (INT)sockaddr_size);
+        DBGFPRINTF((stderr, "SOCKET: connect(%d) -> %"_ld_" (%d)\n", sock, (INT)ret, __threadErrno));
     } while ((ret < 0) && (__threadErrno == EINTR));
 
     if (ret < 0) {
-	int optLen = sizeof(errno);
-	errno = __threadErrno;
+        int optLen = sizeof(errno);
+        errno = __threadErrno;
 #if 0
-	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &errno, &optLen) == SOCKET_ERROR) {
-	    DBGFPRINTF((stderr, "SOCKET: getsockopt(SO_ERROR) failed: %d\n", WSAGetLastError()));
-	}
+        if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &errno, &optLen) == SOCKET_ERROR) {
+            DBGFPRINTF((stderr, "SOCKET: getsockopt(SO_ERROR) failed: %d\n", WSAGetLastError()));
+        }
 #endif // 0
     }
 
@@ -2200,16 +2242,16 @@
     __BEGIN_INTERRUPTABLE__
 #  endif
     do {
-	ret = connect(sock, (struct sockaddr *)&sa, sockaddr_size);
+        ret = connect(sock, (struct sockaddr *)&sa, sockaddr_size);
     } while ((ret < 0)
 #  ifdef __win32__
-	     && (errno = WSAGetLastError())
+             && (errno = WSAGetLastError())
 #  endif
-	     && ((errno == EINTR)
+             && ((errno == EINTR)
 #  ifdef EAGAIN
-		 || (errno == EAGAIN)
+                 || (errno == EAGAIN)
 #  endif
-		));
+                ));
 #  if !defined(__win32__) && !defined(O_NONBLOCK)
     __END_INTERRUPTABLE__
 #  endif
@@ -2222,47 +2264,47 @@
 
     if (ret < 0) {
 # if defined(EINPROGRESS) || defined(EALREADY)
-	if (0
+        if (0
 #  ifdef __win32__
-	    || (errno == WSAEWOULDBLOCK)
+            || (errno == WSAEWOULDBLOCK)
 #  endif
 #  ifdef EINPROGRESS
-	    || (errno == EINPROGRESS)
+            || (errno == EINPROGRESS)
 #  endif
 #  ifdef EALREADY
-	    || (errno == 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
+        ) {
+            /*
+             * 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=%"_ld_" errno=%d __threadErrno=%d\n",
-			(INT)ret, errno, __threadErrno ));
+        {
+            DBGFPRINTF((stderr, "SOCKET: connect failed ret=%"_ld_" errno=%d __threadErrno=%d\n",
+                        (INT)ret, errno, __threadErrno ));
 # ifdef DUMP_ADDRESS
-	    {
-		unsigned char *cp = (unsigned char *)(&sa);
-		int i;
-
-		console_printf("address data:\n");
-		for (i=0; i<sockaddr_size; i++) {
-		    console_printf(" %02x\n", *cp++);
-		}
-	    }
+            {
+                unsigned char *cp = (unsigned char *)(&sa);
+                int i;
+
+                console_printf("address data:\n");
+                for (i=0; i<sockaddr_size; i++) {
+                    console_printf(" %02x\n", *cp++);
+                }
+            }
 # endif
-	    err = __MKSMALLINT(errno);
-	}
+            err = __MKSMALLINT(errno);
+        }
     }
 
 # ifdef __win32__
     {
-	int off = 0;
-	ioctlsocket(sock, FIONBIO, &off);
+        int off = 0;
+        ioctlsocket(sock, FIONBIO, &off);
     }
 # elif defined(O_NONBLOCK) // Linux / Unix
     fcntl(sock, F_SETFL, oldFlags);
@@ -2275,34 +2317,29 @@
 %}.
 
     err notNil ifTrue:[
-	err isSymbol ifTrue:[
-	    self primitiveFailed:err.
-	].
-	lastErrorNumber := err.
-	^ false.
-	"/ Once we will raise an exception instead of returning false (and have to change some code above):
-"/        (OperatingSystem errorHolderForNumber:err) reportError.
+        err isSymbol ifTrue:[
+            self primitiveFailed:err.
+        ].
+        ^ self reportError:err.
     ].
     isAsync ifTrue:[
-	(self writeExceptionWaitWithTimeoutMs:timeout) ifTrue:[
-	    "/ a timeout occurred
-	    "/ should I cancel the connect?
-	    lastErrorNumber := OperatingSystem errorNumberFor:#ETIMEDOUT.
-	    ^ false.
-	].
-	err := self getSocketError.
-	err ~~ 0 ifTrue:[
-	    lastErrorNumber := err.
-	    ^ false.
-	].
+        (self writeExceptionWaitWithTimeoutMs:timeout) ifTrue:[
+            "/ a timeout occurred
+            "/ should I cancel the connect?
+            ^ self reportError:(OperatingSystem errorNumberFor:#ETIMEDOUT).
+        ].
+        err := self getSocketError.
+        err ~~ 0 ifTrue:[
+            ^ self reportError:err.
+        ].
     ].
 
 
     peer := aSocketAddress.
     port isNil ifTrue:[
-	"socket has not been explicitly bound,
-	 after connect it has been bound implicitly - fetch the port"
-	port := self getFullSocketAddress port.
+        "socket has not been explicitly bound,
+         after connect it has been bound implicitly - fetch the port"
+        port := self getFullSocketAddress port.
     ].
     ^ true
 
@@ -2312,11 +2349,22 @@
        sock connectTo:(IPSocketAddress localHost port:21) withTimeout:1000.
        sock
 
+       [
+           |sock|
+           sock := Socket newTCP.
+           sock connectTo:(IPSocketAddress localHost port:21) withTimeout:1000.
+           sock
+       ] on:SocketErrorNotification do:[:ex|
+           ex halt.
+       ].
+
        |sock|
        sock := Socket newTCP.
        sock connectTo:(IPSocketAddress localHost port:9876) withTimeout:2000.
        sock
     "
+
+    "Modified (comment): / 19-01-2018 / 13:35:43 / stefan"
 ! !
 
 !Socket methodsFor:'datagram transmission'!
@@ -2800,6 +2848,25 @@
     self primitiveFailed
 ! !
 
+!Socket methodsFor:'error reporting'!
+
+reportError:osErrorNumber
+    "report an error to the initiator of a Socket operation.
+     We raise a notification for newer code, and also
+     return false for old code not catching the notification."
+
+    |errorHolder|
+
+    lastErrorNumber := osErrorNumber.
+
+    errorHolder := OperatingSystem errorHolderForNumber:osErrorNumber.
+    SocketErrorNotification raiseRequestWith:errorHolder.
+
+    ^ false.
+
+    "Created: / 19-01-2018 / 12:50:00 / stefan"
+! !
+
 !Socket methodsFor:'finalization'!
 
 finalize
@@ -2867,19 +2934,21 @@
     "accept a connection on a server port (created with:'Socket>>newTCP:')
      usage is: (Socket basicNew acceptOn:(Socket newTCP:9999)).
      Return the true if ok; false if not.
+     Notify with a SocketErrorNotification on error.
+
      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."
 
-    |serverSocketHandle addr domainClass newHandle|
+    |serverSocketHandle addr domainClass newHandle err|
 
     handle notNil ifTrue:[
-	^ self errorAlreadyOpen.
+        ^ self errorAlreadyOpen.
     ].
     serverSocketHandle := aServerSocket fileHandle.
     serverSocketHandle isNil ifTrue:[
-	"socket is not open"
-	^ false
+        "socket is not open"
+        ^ self errorNotOpen
     ].
 
     domain := aServerSocket domain.
@@ -2888,7 +2957,7 @@
     "unix domain sockets do not return a valid peer name on accept"
     domainClass := self class socketAddressClassForDomain:domain.
     domainClass isNil ifTrue:[
-	^ self error:'invalid (unsupported) domain'.
+        ^ self error:'invalid (unsupported) domain'.
     ].
     addr := domainClass new.
     newHandle := OperatingSystem socketAccessor new.
@@ -2910,67 +2979,70 @@
 
 # if defined(O_NONBLOCK) && defined(SET_NDELAY)
     if (blocking == false) {
-	flags = fcntl(serverSocket, F_GETFL);
-	fcntl(serverSocket, F_SETFL, flags | O_NONBLOCK);
+        flags = fcntl(serverSocket, F_GETFL);
+        fcntl(serverSocket, F_SETFL, flags | O_NONBLOCK);
     }
 # endif
 
 # ifdef DO_WRAP_CALLS
     do {
-	__threadErrno = 0;
-	alen = sizeof(sa);
-	newSock = (SOCKET)STX_WSA_CALL3("accept", accept, serverSocket, &sa, &alen);
+        __threadErrno = 0;
+        alen = sizeof(sa);
+        newSock = (SOCKET)STX_WSA_CALL3("accept", accept, serverSocket, &sa, &alen);
     } while ((newSock < 0) && (__threadErrno == EINTR));
-    if (newSock < 0) {
-	errno = __threadErrno;
+    if (newSock == -1) {
+        err = __MKSMALLINT(__threadErrno);
     }
 # else
     __BEGIN_INTERRUPTABLE__
     do {
-	alen = sizeof(sa);
-	newSock = accept(serverSocket, (struct sockaddr *) &sa, &alen);
+        alen = sizeof(sa);
+        newSock = accept(serverSocket, (struct sockaddr *) &sa, &alen);
     } while ((newSock < 0) && (errno == EINTR));
     __END_INTERRUPTABLE__
+    if (newSock == -1) {
+        err = __MKSMALLINT(errno);
+    }
 # endif
     DBGFPRINTF((stderr, "SOCKET: accept newSock=%d\n", newSock));
 
 # if defined(O_NDELAY) && defined(SET_NDELAY)
     if (blocking == false) {
-	fcntl(serverSocket, F_SETFL, flags);
+        fcntl(serverSocket, F_SETFL, flags);
     }
 # endif
-
     if (newSock == -1) {
-	DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno));
-	__INST(lastErrorNumber) = __MKSMALLINT(errno);
-	RETURN (false);
+        DBGPRINTF(("SOCKET: accept call failed errno=%d\n", err));
+        goto out;
     }
 
     if (__isNonNilObject(addr)) {
-	OBJ oClass = __qClass(addr);
-	int nInstVars, nInstBytes, objSize;
-	char *addrP;
-
-	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;
-	addrP = (char *)__InstPtr(addr) + nInstBytes;
-	if (objSize < alen) {
-	    DBGPRINTF(("SOCKET: bad addr\n"));
-	    closesocket(newSock);
-	    RETURN (false);
-	}
-
-	/*
-	 * extract the partners address
-	 */
-	memcpy(addrP, (char *)&sa, alen);
+        OBJ oClass = __qClass(addr);
+        int nInstVars, nInstBytes, objSize;
+        char *addrP;
+
+        if (! __isBytes(addr)) {
+            DBGPRINTF(("SOCKET: bad addr\n"));
+            closesocket(newSock);
+            err = @symbol(badAddressArg);
+            goto out;
+        }
+
+        nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
+        nInstBytes = OHDR_SIZE + (nInstVars * sizeof(OBJ));
+        objSize = __qSize(addr) - nInstBytes;
+        addrP = (char *)__InstPtr(addr) + nInstBytes;
+        if (objSize < alen) {
+            DBGPRINTF(("SOCKET: bad addr\n"));
+            closesocket(newSock);
+            err = @symbol(badAddressArgLen);
+            goto out;
+        }
+
+        /*
+         * extract the partners address
+         */
+        memcpy(addrP, (char *)&sa, alen);
     }
 
     /*
@@ -2988,19 +3060,19 @@
 # else // ! __win32__
     fp = fdopen(newSock, "r+");
     if (! fp) {
-	DBGPRINTF(("SOCKET: fdopen call failed\n"));
-	__INST(lastErrorNumber) = __MKSMALLINT(errno);
-	closesocket(newSock);
-	DBGFPRINTF((stderr, "SOCKET: close (fdopen failed) (%d)\n", newSock));
-	RETURN (false);
+        DBGPRINTF(("SOCKET: fdopen call failed\n"));
+        err = __MKSMALLINT(errno);
+        closesocket(newSock);
+        DBGFPRINTF((stderr, "SOCKET: close (fdopen failed) (%d)\n", newSock));
+        goto out;
     }
 # endif // ! __win32__
 
     if ((@global(FileOpenTrace) == true) || __debugging__) {
 # ifdef __win32__
-	console_fprintf(stderr, "fdopen [Socket accept] -> fd: %d (H: %"_lx_")\n", _fd, (INT)newSock);
+        console_fprintf(stderr, "fdopen [Socket accept] -> fd: %d (H: %"_lx_")\n", _fd, (INT)newSock);
 # else
-	console_fprintf(stderr, "fdopen [Socket accept] -> %"_lx_" (fd: %d)\n", (INT)fp, newSock);
+        console_fprintf(stderr, "fdopen [Socket accept] -> %"_lx_" (fd: %d)\n", (INT)fp, newSock);
 # endif
     }
 
@@ -3012,8 +3084,16 @@
     __INST(handleType) = @symbol(socketFilePointer);
 # endif
 #endif /* not NO_SOCKET */
+out:;
 %}.
 
+    err notNil ifTrue:[
+        err isSymbol ifTrue:[
+            self error:err.
+        ].
+        ^ self reportError:err.
+    ].
+
     handle := newHandle.
     buffered := false.
     mode := #readwrite.
@@ -3023,6 +3103,8 @@
     port := aServerSocket port.
 
     ^ true
+
+    "Modified (comment): / 19-01-2018 / 13:35:57 / stefan"
 !
 
 setSocketOption:option argument:arg1 argument:arg2
@@ -3763,6 +3845,7 @@
     "
 ! !
 
+
 !Socket methodsFor:'specials'!
 
 linger:anIntegerOrNil
@@ -4038,14 +4121,6 @@
     ^ self setSocketOption:#'TCP_NODELAY' argument:aBoolean argument:nil.
 ! !
 
-!Socket methodsFor:'testing'!
-
-isSocket
-    "return true, if the receiver is some kind of socket;
-     false returned here - the method is only redefined in Socket."
-
-    ^ true
-! !
 
 !Socket methodsFor:'waiting'!
 
@@ -4118,19 +4193,24 @@
     |newSock|
 
     (self readWaitWithTimeout:timeoutSecondsOrNil) ifTrue:[
-	"a timeout occurred - no connection within timeout"
-	^ nil
+        "a timeout occurred - no connection within timeout"
+        self reportError:(OperatingSystem errorNumberFor:#ETIMEDOUT).
+        ^ nil.
     ].
     self isOpen ifFalse:[
-	"socket has been closed while waiting"
-	^ nil.
+        "I have been closed while waiting"
+        ^ self errorNotOpen.
     ].
+
+    "ok, a connection is present - accept it"
     newSock := self class new.
     (newSock primAcceptOn:self blocking:false) ifFalse:[
-	"should raise an error here"
-	^ nil
+        "should raise an error here - primitive code raises a notification"
+        ^ nil
     ].
     ^ newSock
+
+    "Modified (comment): / 19-01-2018 / 13:54:17 / stefan"
 ! !
 
 !Socket class methodsFor:'documentation'!