Socket.st
branchjv
changeset 4213 739af6adeb3a
parent 4093 3d5eab86719e
parent 4192 5b2c3f2c8d13
child 4214 5654b7964b47
--- 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"