--- 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'!