--- a/Socket.st Fri Jan 19 15:43:48 2018 +0100
+++ b/Socket.st Fri Jan 19 19:24:11 2018 +0100
@@ -761,7 +761,7 @@
^ self newTCPclientToAddress:aHostAddress port:aService withTimeout:nil
!
-newTCPclientToAddress:aSocketAddressOrByteArray port:aService withTimeout:millis
+newTCPclientToAddress:aSocketAddressOrByteArray port:aService withTimeout:milliSecondsOrTimeDuration
"create a new TCP client socket connecting to a service.
Return a socket instance if ok, nil on failure.
If the millis arg is nonNil, stop trying to connect after that many milliseconds
@@ -770,23 +770,25 @@
|port socketAddress|
aService isString ifTrue:[
- port := self portOfService:aService protocol:#tcp.
+ port := self portOfService:aService protocol:#tcp.
] ifFalse:[
- port := aService.
+ port := aService.
].
socketAddress := aSocketAddressOrByteArray isSocketAddress
- ifTrue:[aSocketAddressOrByteArray]
- ifFalse:[
- "Passing ByteArrays is obsolete and only supported for IPv4"
- IPSocketAddress hostAddress:aSocketAddressOrByteArray
- ].
+ ifTrue:[aSocketAddressOrByteArray]
+ ifFalse:[
+ "Passing ByteArrays is obsolete and only supported for IPv4"
+ IPSocketAddress hostAddress:aSocketAddressOrByteArray
+ ].
port notNil ifTrue:[
- socketAddress port:port.
+ socketAddress port:port.
].
- ^ self newTCPclientToAddress:socketAddress withTimeout:millis
+ ^ self newTCPclientToAddress:socketAddress withTimeout:milliSecondsOrTimeDuration
+
+ "Modified (format): / 19-01-2018 / 18:26:51 / stefan"
!
-newTCPclientToAddress:aSocketAddress withTimeout:millis
+newTCPclientToAddress:aSocketAddress withTimeout:milliSecondsOrTimeDuration
"create a new TCP client socket connecting to a service.
Return a socket instance if ok, nil on failure.
If the millis arg is nonNil, stop trying to connect after that many milliseconds
@@ -795,15 +797,18 @@
|socket|
socket := self domain:aSocketAddress domain type:#stream.
- (socket connectTo:aSocketAddress withTimeout:millis) ifFalse:[
- socket close.
- ^ nil
+ ^ [
+ (socket connectTo:aSocketAddress withTimeout:milliSecondsOrTimeDuration)
+ ifTrue:[socket] ifFalse:[socket close. nil]
+ ] ifCurtailed:[
+ socket close.
].
- ^ socket.
"
- self newTCPclientToAddress:(IPv6SocketAddress hostName:'www.exept.de' port:80) withTimeout:nil
+ self newTCPclientToAddress:(IPv6SocketAddress hostName:'www.exept.de' port:80) withTimeout:nil
"
+
+ "Modified (format): / 19-01-2018 / 18:22:30 / stefan"
!
newTCPclientToHost:hostNameOrAddress port:aPortOrServiceName
@@ -828,44 +833,52 @@
"Created: 31.10.1995 / 18:54:11 / cg"
!
-newTCPclientToHost:hostNameOrAddress port:aPortOrServiceName domain:aDomainSymbolOrNil withTimeout:millis
+newTCPclientToHost:hostNameOrAddress port:aPortOrServiceName domain:aDomainSymbolOrNil withTimeout:milliSecondsOrTimeDuration
"create a new TCP client socket connecting to a service on hostNameOrAddress.
If hostNameOrAddress is a string, try all the resolved addresses.
Return a socket instance if ok, nil on failure.
Set aDomainSymbolOrNil to #AF_INET of #AF_INET6 to connect via a defined protocol.
Set aDomainSymbolOrNil to nil, to try all protocols.
- If the millis arg is nonNil, stop trying to connect after that many milliseconds
+ If the milliSecondsOrTimeDuration arg is nonNil, stop trying to connect after that many milliSecondsOrTimeDurationeconds
and return nil."
- |socket addressList lastDomainSymbol|
+ |socket addressList lastDomainSymbol lastNotification|
hostNameOrAddress isString ifFalse:[
- ^ self newTCPclientToAddress:hostNameOrAddress port:aPortOrServiceName withTimeout:millis.
+ ^ self newTCPclientToAddress:hostNameOrAddress port:aPortOrServiceName withTimeout:milliSecondsOrTimeDuration.
].
addressList := SocketAddress
- allForHostName:hostNameOrAddress
- serviceName:aPortOrServiceName
- domain:aDomainSymbolOrNil
- type:#stream.
+ allForHostName:hostNameOrAddress
+ serviceName:aPortOrServiceName
+ domain:aDomainSymbolOrNil
+ type:#stream.
addressList do:[:eachAddress|
- |domainSymbol|
-
- domainSymbol := eachAddress domain.
- domainSymbol ~~ lastDomainSymbol ifTrue:[
- socket notNil ifTrue:[
- socket close.
- ].
- socket := self new domain:domainSymbol type:#stream.
- lastDomainSymbol := domainSymbol.
- ].
- (socket connectTo:eachAddress withTimeout:millis) ifTrue:[
- ^ socket.
- ].
+ |domainSymbol|
+
+ domainSymbol := eachAddress domain.
+ domainSymbol ~~ lastDomainSymbol ifTrue:[
+ socket notNil ifTrue:[
+ socket close.
+ ].
+ socket := self new domain:domainSymbol type:#stream.
+ lastDomainSymbol := domainSymbol.
+ ].
+ [
+ (socket connectTo:eachAddress withTimeout:milliSecondsOrTimeDuration) ifTrue:[
+ ^ socket.
+ ].
+ ] on:SocketErrorNotification do:[:ex|
+ lastNotification := ex.
+ ].
].
socket notNil ifTrue:[
- socket close.
+ socket close.
+ ].
+ lastNotification notNil ifTrue:[
+ "if someone is interested in the notification - raise the last one"
+ lastNotification raiseRequest.
].
^ nil.
@@ -876,10 +889,10 @@
Socket newTCPclientToHost:'localhost' port:'nntp' withTimeout:1000
"
- "Modified: / 21-02-2017 / 21:36:16 / stefan"
+ "Modified: / 19-01-2018 / 18:12:29 / stefan"
!
-newTCPclientToHost:hostNameOrAddress port:aPortOrServiceName withTimeout:millis
+newTCPclientToHost:hostNameOrAddress port:aPortOrServiceName withTimeout:milliSecondsOrTimeDuration
"create a new TCP client socket connecting to a service on hostNameOrAddress.
If hostNameOrAddress is a string, try all the resolved addresses regardless
whether for IPv4 or IPv6.
@@ -888,10 +901,12 @@
and return nil."
^ self
- newTCPclientToHost:hostNameOrAddress
- port:aPortOrServiceName
- domain:self defaultIpDomainForConnect
- withTimeout:millis
+ newTCPclientToHost:hostNameOrAddress
+ port:aPortOrServiceName
+ domain:self defaultIpDomainForConnect
+ withTimeout:milliSecondsOrTimeDuration
+
+ "Modified (format): / 19-01-2018 / 18:24:57 / stefan"
!
newTCPserverAtAnonymousPort
@@ -974,7 +989,7 @@
!
-newUNIXclientTo:pathName withTimeout:millis
+newUNIXclientTo:pathName withTimeout:milliSecondsOrTimeDuration
"create a new UNIX client socket connecting to a pathname.
Return a socket instance if ok, nil on failure.
If the millis arg is nonNil, stop trying to connect after that many milliseconds
@@ -982,20 +997,30 @@
If the system does not support unix domain sockets (i.e. VMS or MSDOS),
return nil."
- |newSock|
-
- newSock := self newUNIX.
- newSock notNil ifTrue:[
- (newSock connectTo:(UDSocketAddress name:pathName) withTimeout:millis) ifFalse:[
- newSock close.
- ^ nil
- ]
+ |socket|
+
+ socket := self newUNIX.
+ socket isNil ifTrue:[
+ ^ nil.
].
- ^ newSock
+ ^ [
+ (socket connectTo:(UDSocketAddress name:pathName) withTimeout:milliSecondsOrTimeDuration)
+ ifTrue:[socket] ifFalse:[socket close. nil]
+ ] ifCurtailed:[
+ socket close.
+ ].
"
- Socket newUNIXclientTo:'/tmp/foo'
+ Socket newUNIXclientTo:'/tmp/foo'
+
+ [
+ Socket newUNIXclientTo:'/tmp/foo'
+ ] on:SocketErrorNotification do:[:ex|
+ ex halt.
+ ]
"
+
+ "Modified (format): / 19-01-2018 / 18:23:24 / stefan"
!
newUNIXserverAt:pathName
@@ -2088,7 +2113,7 @@
^ self connectTo:hostOrPathName port:portNrOrName withTimeout:nil
!
-connectTo:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil withTimeout:timeout
+connectTo:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil withTimeout:milliSecondsOrTimeDuration
<resource: #obsolete>
"Backward compatibility connect; connect to port, portNrOrNameOrNil on host, hostOrPathNameOrSocketAddr.
For backward compatibility, hostOrPathNameOrSocketAddr may be also a string or a byteArray,
@@ -2098,7 +2123,7 @@
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."
+ or milliSecondsOrTimeDuration milliseconds have passed."
|domainClass socketAddress|
@@ -2125,7 +2150,7 @@
].
].
- ^ self connectTo:socketAddress withTimeout:timeout.
+ ^ self connectTo:socketAddress withTimeout:milliSecondsOrTimeDuration.
"
|sock|
@@ -2139,10 +2164,10 @@
sock
"
- "Modified (comment): / 19-01-2018 / 13:38:10 / stefan"
+ "Modified (comment): / 19-01-2018 / 17:48:08 / stefan"
!
-connectTo:aSocketAddress withTimeout:timeout
+connectTo:aSocketAddress withTimeout:milliSecondsOrTimeDuration
"Connect to a SocketAddress.
Return true if ok, false otherwise.
@@ -2151,7 +2176,7 @@
The current process will block (but not the whole Smalltalk) until the connection is established,
or timeout milliseconds have passed."
- |isAsync err|
+ |isAsync err timeoutMs milliSeconds|
handle isNil ifTrue:[
^ self errorNotOpen
@@ -2323,7 +2348,11 @@
^ self reportError:err.
].
isAsync ifTrue:[
- (self writeExceptionWaitWithTimeoutMs:timeout) ifTrue:[
+ milliSeconds := milliSecondsOrTimeDuration.
+ milliSecondsOrTimeDuration isTimeDuration ifTrue:[
+ milliSeconds := milliSecondsOrTimeDuration asMilliseconds.
+ ].
+ (self writeExceptionWaitWithTimeoutMs:milliSeconds) ifTrue:[
"/ a timeout occurred
"/ should I cancel the connect?
^ self reportError:(OperatingSystem errorNumberFor:#ETIMEDOUT).
@@ -2364,7 +2393,7 @@
sock
"
- "Modified (comment): / 19-01-2018 / 13:35:43 / stefan"
+ "Modified: / 19-01-2018 / 17:57:36 / stefan"
! !
!Socket methodsFor:'datagram transmission'!
@@ -3923,7 +3952,7 @@
|millis|
handle isNil ifTrue:[
- ^ self errorNotOpen
+ ^ self errorNotOpen
].
%{
#if defined(SO_RCVTIMEO) && defined(SOL_SOCKET)
@@ -3935,52 +3964,82 @@
len = sizeof(struct timeval);
if (getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, &len) == 0) {
- __millis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
- millis = __mkSmallInteger(__millis);
+ __millis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+ millis = __mkSmallInteger(__millis);
# if 0
- console_fprintf(stderr, "getsockopt -> s:%d us:%d -> millis:%d\n", tv.tv_sec, tv.tv_usec, __millis);
+ console_fprintf(stderr, "getsockopt -> s:%d us:%d -> millis:%d\n", tv.tv_sec, tv.tv_usec, __millis);
# endif
} else {
- console_fprintf(stderr, "Socket [warning]: getsockopt %d failed; errno=%d\n", sock, errno);
+ console_fprintf(stderr, "Socket [warning]: getsockopt %d failed; errno=%d\n", sock, errno);
}
#endif
%}.
- millis notNil ifTrue:[^ millis / 1000 ].
- ^ nil
+ ^ millis
+
+ "
+ Socket newTCP receiveTimeout
+ "
+
+ "Modified: / 19-01-2018 / 19:15:17 / stefan"
!
-receiveTimeout:seconds
+receiveTimeout:secondsOrTimeDuration
"set the receive timeout - for special applications only.
Not all operatingSystems offer this functionality
- (returns false, if unsupported)"
+ (returns false, if unsupported).
+
+ From linux manpage:
+ SO_RCVTIMEO and SO_SNDTIMEO
+ Specify the receiving or sending timeouts until reporting an error. The argument is a
+ struct timeval. If an input or output function blocks for this period of time, and data has
+ been sent or received, the return value of that function will be the amount of data trans-
+ ferred; if no data has been transferred and the timeout has been reached, then -1 is
+ returned with errno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just as if
+ the socket was specified to be nonblocking. If the timeout is set to zero (the default),
+ then the operation will never timeout. Timeouts only have effect for system calls that per-
+ form socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect
+ for select(2), poll(2), epoll_wait(2), and so on."
|millis|
handle isNil ifTrue:[
- ^ self errorNotOpen
+ ^ self errorNotOpen
].
- millis := (seconds * 1000) rounded.
+ secondsOrTimeDuration isTimeDuration ifTrue:[
+ millis := secondsOrTimeDuration getMilliseconds.
+ ] ifFalse:[
+ millis := (secondsOrTimeDuration * 1000) rounded.
+ ].
+
%{
#if defined(SO_RCVTIMEO) && defined(SOL_SOCKET)
if (__isSmallInteger(millis)) {
- OBJ fp = __INST(handle);
- SOCKET sock = SOCKET_FROM_FILE_OBJECT(fp);
- int __millis = __intVal(millis);
- struct timeval tv = {0, 0};
-
- tv.tv_sec = __millis / 1000;
- tv.tv_usec = (__millis % 1000) * 1000;
+ OBJ fp = __INST(handle);
+ SOCKET sock = SOCKET_FROM_FILE_OBJECT(fp);
+ int __millis = __intVal(millis);
+ struct timeval tv = {0, 0};
+
+ tv.tv_sec = __millis / 1000;
+ tv.tv_usec = (__millis % 1000) * 1000;
# if 0
- console_fprintf(stderr, "setsockopt -> millis:%d -> s:%d us:%d \n", __millis, tv.tv_sec, tv.tv_usec);
+ console_fprintf(stderr, "setsockopt -> millis:%d -> s:%d us:%d \n", __millis, tv.tv_sec, tv.tv_usec);
# endif
- if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(struct timeval)) == 0) {
- RETURN(true);
- }
- console_fprintf(stderr, "Socket [warning]: setsockopt %d failed; errno=%d\n", sock, errno);
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(struct timeval)) == 0) {
+ RETURN(true);
+ }
+ console_fprintf(stderr, "Socket [warning]: setsockopt %d failed; errno=%d\n", sock, errno);
}
#endif
%}.
^ false
+
+ "
+ Socket newTCP
+ receiveTimeout:5s;
+ receiveTimeout
+ "
+
+ "Modified (comment): / 19-01-2018 / 19:14:49 / stefan"
!
sendBufferSize
@@ -4043,7 +4102,7 @@
|millis|
handle isNil ifTrue:[
- ^ self errorNotOpen
+ ^ self errorNotOpen
].
%{
#if defined(SO_SNDTIMEO) && defined(SOL_SOCKET)
@@ -4055,52 +4114,80 @@
len = sizeof(struct timeval);
if (getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, &len) == 0) {
- __millis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
- millis = __mkSmallInteger(__millis);
+ __millis = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+ millis = __mkSmallInteger(__millis);
# if 0
- console_fprintf(stderr, "getsockopt -> s:%d us:%d -> millis:%d\n", tv.tv_sec, tv.tv_usec, __millis);
+ console_fprintf(stderr, "getsockopt -> s:%d us:%d -> millis:%d\n", tv.tv_sec, tv.tv_usec, __millis);
# endif
} else {
- console_fprintf(stderr, "Socket [warning]: getsockopt %d failed; errno=%d\n", sock, errno);
+ console_fprintf(stderr, "Socket [warning]: getsockopt %d failed; errno=%d\n", sock, errno);
}
#endif
%}.
- millis notNil ifTrue:[^ millis / 1000 ].
- ^ nil
+ ^ millis
+
+ "
+ Socket newTCP sendTimeout
+ "
+
+ "Modified (comment): / 19-01-2018 / 19:16:23 / stefan"
!
-sendTimeout:seconds
+sendTimeout:secondsOrTimeDuration
"set the send timeout - for special applications only.
Not all operatingSystems offer this functionality
- (returns false, if unsupported)"
+ (returns false, if unsupported).
+ From linux manpage:
+ SO_RCVTIMEO and SO_SNDTIMEO
+ Specify the receiving or sending timeouts until reporting an error. The argument is a
+ struct timeval. If an input or output function blocks for this period of time, and data has
+ been sent or received, the return value of that function will be the amount of data trans-
+ ferred; if no data has been transferred and the timeout has been reached, then -1 is
+ returned with errno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just as if
+ the socket was specified to be nonblocking. If the timeout is set to zero (the default),
+ then the operation will never timeout. Timeouts only have effect for system calls that per-
+ form socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect
+ for select(2), poll(2), epoll_wait(2), and so on."
|millis|
handle isNil ifTrue:[
- ^ self errorNotOpen
+ ^ self errorNotOpen
].
- millis := (seconds * 1000) rounded.
+ secondsOrTimeDuration isTimeDuration ifTrue:[
+ millis := secondsOrTimeDuration getMilliseconds.
+ ] ifFalse:[
+ millis := (secondsOrTimeDuration * 1000) rounded.
+ ].
%{
#if defined(SO_SNDTIMEO) && defined(SOL_SOCKET)
if (__isSmallInteger(millis)) {
- OBJ fp = __INST(handle);
- SOCKET sock = SOCKET_FROM_FILE_OBJECT(fp);
- int __millis = __intVal(millis);
- struct timeval tv = {0, 0};
-
- tv.tv_sec = __millis / 1000;
- tv.tv_usec = (__millis % 1000) * 1000;
+ OBJ fp = __INST(handle);
+ SOCKET sock = SOCKET_FROM_FILE_OBJECT(fp);
+ int __millis = __intVal(millis);
+ struct timeval tv = {0, 0};
+
+ tv.tv_sec = __millis / 1000;
+ tv.tv_usec = (__millis % 1000) * 1000;
# if 0
- console_fprintf(stderr, "setsockopt -> millis:%d -> s:%d us:%d \n", __millis, tv.tv_sec, tv.tv_usec);
+ console_fprintf(stderr, "setsockopt -> millis:%d -> s:%d us:%d \n", __millis, tv.tv_sec, tv.tv_usec);
# endif
- if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, sizeof(struct timeval)) == 0) {
- RETURN(true);
- }
- console_fprintf(stderr, "Socket [warning]: setsockopt %d failed; errno=%d\n", sock, errno);
+ if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, sizeof(struct timeval)) == 0) {
+ RETURN(true);
+ }
+ console_fprintf(stderr, "Socket [warning]: setsockopt %d failed; errno=%d\n", sock, errno);
}
#endif
%}.
^ false
+
+ "
+ Socket newTCP
+ sendTimeout:5s;
+ sendTimeout
+ "
+
+ "Modified (comment): / 19-01-2018 / 19:12:51 / stefan"
!
setTCPCork:aBoolean
@@ -4124,7 +4211,7 @@
!Socket methodsFor:'waiting'!
-waitForNewConnectionOrDataOnAny:otherConnections timeout:timeoutSeconds
+waitForNewConnectionOrDataOnAny:otherConnections timeout:secondsOrTimeDurationOrNil
"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.
@@ -4135,7 +4222,7 @@
server application."
- |wasBlocked sema|
+ |wasBlocked sema timeoutMs|
"first, a quick check if data is already available"
self canReadWithoutBlocking ifTrue:[
@@ -4148,6 +4235,15 @@
].
"check again - prevent incoming interrupts from disturbing our setup"
+
+ secondsOrTimeDurationOrNil notNil ifTrue:[
+ secondsOrTimeDurationOrNil isTimeDuration ifTrue:[
+ timeoutMs := secondsOrTimeDurationOrNil getMilliseconds.
+ ] ifFalse:[
+ timeoutMs := secondsOrTimeDurationOrNil * 1000.
+ ]
+ ].
+
wasBlocked := OperatingSystem blockInterrupts.
[
sema := Semaphore name:'multiReadWait'.
@@ -4155,8 +4251,8 @@
Processor signal:sema onInput:(aConnection fileDescriptor).
].
Processor signal:sema onInput:(self fileDescriptor).
- timeoutSeconds notNil ifTrue:[
- Processor signal:sema afterSeconds:timeoutSeconds
+ timeoutMs notNil ifTrue:[
+ Processor signal:sema afterMilliseconds:timeoutMs
].
Processor activeProcess state:#ioWait.
sema wait.
@@ -4180,9 +4276,10 @@
^ nil
"Modified: / 09-08-2017 / 11:59:50 / cg"
+ "Modified: / 19-01-2018 / 18:59:17 / stefan"
!
-waitForNewConnectionWithTimeout:timeoutSecondsOrNil
+waitForNewConnectionWithTimeout:secondsOrTimeDurationOrNil
"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.
@@ -4192,7 +4289,7 @@
|newSock|
- (self readWaitWithTimeout:timeoutSecondsOrNil) ifTrue:[
+ (self readWaitWithTimeout:secondsOrTimeDurationOrNil) ifTrue:[
"a timeout occurred - no connection within timeout"
self reportError:(OperatingSystem errorNumberFor:#ETIMEDOUT).
^ nil.
@@ -4210,7 +4307,7 @@
].
^ newSock
- "Modified (comment): / 19-01-2018 / 13:54:17 / stefan"
+ "Modified (format): / 19-01-2018 / 18:53:15 / stefan"
! !
!Socket class methodsFor:'documentation'!