--- a/Socket.st Fri Nov 18 21:26:37 2016 +0000
+++ b/Socket.st Fri Nov 18 21:28:24 2016 +0000
@@ -1,5 +1,3 @@
-"{ Encoding: utf8 }"
-
"
COPYRIGHT (c) 1992 by Claus Gittinger
All Rights Reserved
@@ -321,7 +319,7 @@
] whileTrue.
sock close.
- 'dont know enough of the ftp protocol to continue here ...'
+ 'don't know enough of the ftp protocol to continue here ...'
[exEnd]
@@ -2012,13 +2010,19 @@
!Socket methodsFor:'closing'!
-finalize
- self linger:0. "/ discard buffered data
- super finalize.
+abortAndClose
+ "immediately abort the connection:
+ discard buffered data and close the stream"
+
+ self linger:0.
+ self close.
!
shutDown
- "shutDown and close the socket"
+ "shutDown (initiate a graceful close)
+ and close (free the filedescriptor) the socket.
+ The close will return immediately and buffered data will be sent in the
+ background, unless you set linger"
self shutdown:2.
self close
@@ -2036,8 +2040,11 @@
shutDownOutput
"shutDown the output side of the socket.
Any write to the socket will signal end-of-file from now on.
- An orderly realease (TCP FIN) will be initiated after the last buffered data
- has been sent, so the other side will get a end-of-file condition eventually."
+ An orderly release (TCP FIN) will be initiated after the last buffered data
+ has been sent, so the other side will get a end-of-file condition eventually.
+ If you set linger > 0, the operation will wait until buffered data
+ has been delivered to the peer.
+ Otherwise the operation returns immediately."
self shutdown:1.
! !
@@ -2808,6 +2815,13 @@
self primitiveFailed
! !
+!Socket methodsFor:'finalization'!
+
+finalize
+ self linger:0. "/ do an abortive release - discard buffered data
+ self closeFile. "/ does not wait due to abortive release.
+! !
+
!Socket methodsFor:'initialization'!
initialize
@@ -2816,73 +2830,6 @@
eolMode := nil.
! !
-!Socket protectedMethodsFor:'low level'!
-
-closeFile
- "low level close - may be redefined in subclasses
- Don't send this message, send #close instead"
-
- |fp error|
-
- fp := handle.
-
-%{
- int rslt;
-
- if (fp == nil) {
- error = @symbol(errorNotOpen);
- goto out;
- }
-
- if (__INST(handleType) == @symbol(socketHandle)) {
- SOCKET socket = SOCKET_FROM_FILE_OBJECT(fp);
-
- if (@global(FileOpenTrace) == true) {
- console_fprintf(stderr, "close socket [ExternalStream] %"_lx_"\n", socket);
- }
-
- // whether the close() will be successful or not - the handle is invalid now!
- __INST(handle) = nil;
- do {
-#ifdef __win32__
- rslt = __STX_WSA_NOINT_CALL1("closesocket", closesocket, socket);
-#else
- rslt = close(socket);
-#endif
- } while((rslt < 0) && (__threadErrno == EINTR));
- if (rslt == 0) {
- RETURN(self);
- }
- error = __mkSmallInteger(__threadErrno);
- }
-
-out:;
-%}.
-
- error notNil ifTrue:[
- error == #errorNotOpen ifTrue:[
- self errorNotOpen.
- ].
- error isInteger ifTrue:[
- lastErrorNumber := error.
- self writeError:error.
- ^ self.
- ].
- self primitiveFailed:error.
- ^ self.
- ].
-
- super closeFile.
-
- "/ fallback for rel5
-
- fp := handle.
- fp notNil ifTrue:[
- handle := nil.
- self closeFile:fp
- ]
-! !
-
!Socket methodsFor:'low level'!
getSocketAdress
@@ -2942,20 +2889,21 @@
|serverSocketHandle addr domainClass newHandle|
handle notNil ifTrue:[
- ^ self errorAlreadyOpen
+ ^ self errorAlreadyOpen.
+ ].
+ serverSocketHandle := aServerSocket fileHandle.
+ serverSocketHandle isNil ifTrue:[
+ "socket is not open"
+ ^ false
].
domain := aServerSocket domain.
socketType := aServerSocket type.
handleType := aServerSocket handleType.
- serverSocketHandle := aServerSocket fileHandle.
- serverSocketHandle isNil ifTrue:[
- ^ self error:'invalid server socket'
- ].
"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.
@@ -2977,25 +2925,25 @@
# 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;
+ errno = __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__
# endif
@@ -3003,41 +2951,41 @@
# 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", errno));
+ __INST(lastErrorNumber) = __MKSMALLINT(errno);
+ RETURN (false);
}
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);
+ 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);
}
/*
@@ -3055,19 +3003,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"));
+ __INST(lastErrorNumber) = __MKSMALLINT(errno);
+ closesocket(newSock);
+ DBGFPRINTF((stderr, "SOCKET: close (fdopen failed) (%d)\n", newSock));
+ RETURN (false);
}
# 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
}
@@ -3835,16 +3783,16 @@
linger:anIntegerOrNil
"set the linger behavior on close:
anIntegerOrNil == nil: close returns immediately, socket tries
- to send buffered data in background.
+ to send buffered data in background.
anIntegerOrNil == 0: close returns immediately, bufferd data is discarded.
anIntegerOrNil > 0: close waits this many seconds for buffered data
- to be delivered, after this time buffered data is
- discarded and close returns"
+ to be delivered, after this time buffered data is
+ discarded and close returns with an error"
^ self
- setSocketOption:#'SO_LINGER'
- argument:anIntegerOrNil notNil
- argument:anIntegerOrNil.
+ setSocketOption:#'SO_LINGER'
+ argument:anIntegerOrNil notNil
+ argument:anIntegerOrNil.
!
receiveBufferSize
@@ -4177,6 +4125,10 @@
"a timeout occurred - no connection within timeout"
^ nil
].
+ self isOpen ifFalse:[
+ "socket has been closed while waiting"
+ ^ nil.
+ ].
newSock := self class new.
(newSock primAcceptOn:self blocking:false) ifFalse:[
"should raise an error here"