Default for close - linger in background instead 30s in foreground
authorStefan Vogel <sv@exept.de>
Mon, 08 Oct 2012 09:45:43 +0200
changeset 2823 10179ccfae5d
parent 2822 371789d0fe49
child 2824 b00dc482dd03
Default for close - linger in background instead 30s in foreground comment/format in: #documentation #examples #shutDownOutput changed: #closeFile #sendTo:buffer:start:for:flags: #shutdown:
Socket.st
--- a/Socket.st	Wed Oct 03 16:50:45 2012 +0200
+++ b/Socket.st	Mon Oct 08 09:45:43 2012 +0200
@@ -20,6 +20,7 @@
 !
 
 !Socket primitiveDefinitions!
+
 %{
 
 /* #define DGRAM_DEBUG /* */
@@ -40,7 +41,10 @@
 # endif
 
 # define WRAP_STDIO
-# define SET_LINGER_WHEN_CREATING_SOCKET
+// The default is linger until all data is sent in background
+// so the close on the socket is non-blocking
+// linger.onoff=off linger.time= *irrelevant*
+//# define SET_LINGER_WHEN_CREATING_SOCKET
 
 /*
  * mhmh - WIN32-fclose  has a problem in trying to close() the socket
@@ -259,424 +263,421 @@
     which are meant to be compatible to ST-80's UnixSocketAccessor interface.
 
     TODO: cleanup historic leftovers, implement other than inet domain stuff.
-	  (mhmh - how can I test those ?)
-	  change to raise more signals on errors.
-	  Help - could someone who has a linux machine connected to an appletalk
-		 net please test this (and send bug fixes ...)
+          (mhmh - how can I test those ?)
+          change to raise more signals on errors.
 
     [author:]
-	Claus Gittinger
+        Claus Gittinger
 "
 !
 
 examples
 "
     example (get help info from an nntp server):
-									[exBegin]
-	|sock host|
-
-	host := OperatingSystem getEnvironment:'NNTPSERVER'.
-
-	sock := Socket newTCPclientToHost:host port:'nntp'.
-	sock isNil ifTrue:[
-	    self warn:'no nntp daemon is running'.
-	    ^ self
-	].
-	Transcript showCR:sock nextLine.
-	sock buffered:false.
-
-	sock nextPutAll:'HELP'; cr.
-	[:exit |
-	    |line|
-
-	    line := sock nextLine.
-	    line = '.' ifTrue:[exit value:nil].
-	    Transcript showCR:line.
-	] loopWithExit.
-	sock close
-									[exEnd]
+                                                                        [exBegin]
+        |sock host|
+
+        host := OperatingSystem getEnvironment:'NNTPSERVER'.
+
+        sock := Socket newTCPclientToHost:host port:'nntp'.
+        sock isNil ifTrue:[
+            self warn:'no nntp daemon is running'.
+            ^ self
+        ].
+        Transcript showCR:sock nextLine.
+        sock buffered:false.
+
+        sock nextPutAll:'HELP'; cr.
+        [:exit |
+            |line|
+
+            line := sock nextLine.
+            line = '.' ifTrue:[exit value:nil].
+            Transcript showCR:line.
+        ] loopWithExit.
+        sock close
+                                                                        [exEnd]
 
 
     example (connect to finger daemon, get users entry):
-									[exBegin]
-	|sock host entry|
-
-	host := OperatingSystem getHostName.
-
-	sock := Socket newTCPclientToHost:host port:'finger'.
-	sock isNil ifTrue:[
-	    self warn:'no finger daemon is running'.
-	    ^ self
-	].
-	sock useCRLF:true.
-	sock buffered:false.
-	sock isNil ifTrue:[
-	    Transcript showCR:'cannot connect to local finger daemon'
-	] ifFalse:[
-	    sock nextPutAll:(OperatingSystem getLoginName).
-	    sock cr.
-
-	    entry := sock nextLine.
-	    Transcript showCR:entry.
-
-	    sock close
-	]
-									[exEnd]
+                                                                        [exBegin]
+        |sock entry|
+
+        sock := Socket newTCPclientToHost:'localhost' port:'finger'.
+        sock isNil ifTrue:[
+            self warn:'no finger daemon is running'.
+            ^ self
+        ].
+        sock useCRLF:true.
+        sock buffered:false.
+        sock isNil ifTrue:[
+            Transcript showCR:'cannot connect to local finger daemon'
+        ] ifFalse:[
+            sock nextPutAll:(OperatingSystem getLoginName).
+            sock cr.
+
+            entry := sock nextLine.
+            Transcript showCR:entry.
+
+            sock close
+        ]
+                                                                        [exEnd]
 
     example (connect to an ftp server):
-									[exBegin]
-	|sock host|
-
-	host := OperatingSystem getHostName.
-	sock := Socket newTCPclientToHost:host port:'ftp'.
-
-	sock buffered:false.
-	Transcript showCR:sock nextLine.
-	sock nextPutAll:('USER ' , 'anonymous'); cr.
-	Transcript showCR:sock nextLine.
-	sock nextPutAll:('PASS ' , 'fooBar'); cr.
-	Transcript showCR:sock nextLine.
-	sock nextPutAll:'LIST'; cr.
-	Transcript showCR:sock nextLine.
-	sock close.
-
-	'dont know enough of the ftp protocol to continue here ...'
-									[exEnd]
+                                                                        [exBegin]
+        |sock|
+
+        sock := Socket newTCPclientToHost:'www.exept.de' port:'ftp'.
+
+        sock buffered:false.
+        Transcript showCR:sock nextLine.
+        sock nextPutAll:('USER ' , 'anonymous'); cr.
+        Transcript showCR:sock nextLine.
+        sock nextPutAll:('PASS ' , 'fooBar'); cr.
+        Transcript showCR:sock nextLine.
+        sock nextPutAll:'PASV'; cr.
+        Transcript showCR:sock nextLine.
+        sock nextPutAll:'LIST'; cr.
+        Transcript showCR:sock nextLine.
+        sock close.
+
+        'dont know enough of the ftp protocol to continue here ...'
+                                                                        [exEnd]
 
 
     example (connect to an snmp server [UDP]):
-									[exBegin]
-	|sock port|
-
-	sock := Socket newUDP.
-	port := Socket portOfService:'snmp'.
-	sock connectTo:(OperatingSystem getHostName) port:port.
-	sock buffered:false.
-	Transcript showCR:'got it'.
-	sock close.
-									[exEnd]
+                                                                        [exBegin]
+        |sock port|
+
+        sock := Socket newUDP.
+        port := Socket portOfService:'snmp'.
+        sock connectTo:'localhost' port:port.
+        sock buffered:false.
+        Transcript showCR:'got it'.
+        sock close.
+                                                                        [exEnd]
 
 
     example (await connection from a client and read some data):
-									[exBegin]
-	|connectSock sock|
-
-	connectSock := Socket newTCPserverAtPort:9998.
-	connectSock isNil ifTrue:[
-	    Transcript showCR:'socket setup failed.'.
-	] ifFalse:[
-	    Transcript showCR:'listen ..'.
-	    (connectSock listenFor:5) ifFalse:[
-		Transcript showCR:'listen failed.'.
-	    ] ifTrue:[
-		Transcript showCR:'wait'.
-		connectSock readWait.
-		Transcript showCR:'accept'.
-		sock := connectSock accept.
-		sock isNil ifTrue:[
-		    Transcript showCR:'accept failed.'.
-		] ifFalse:[
-		    sock buffered:false.
-		    Transcript showCR:'server: got it'.
-		    'can now do transfer via sock'.
-		    Transcript showCR:'read'.
-		    Transcript showCR:('got: ' , sock nextLine).
-
-		    Transcript showCR:'close'.
-		    sock close
-		].
-		connectSock close.
-	    ]
-	]
-									[exEnd]
+                                                                        [exBegin]
+        |connectSock sock|
+
+        connectSock := Socket newTCPserverAtPort:9998.
+        connectSock isNil ifTrue:[
+            Transcript showCR:'socket setup failed.'.
+        ] ifFalse:[
+            Transcript showCR:'listen ..'.
+            (connectSock listenFor:5) ifFalse:[
+                Transcript showCR:'listen failed.'.
+            ] ifTrue:[
+                Transcript showCR:'wait'.
+                connectSock readWait.
+                Transcript showCR:'accept'.
+                sock := connectSock accept.
+                sock isNil ifTrue:[
+                    Transcript showCR:'accept failed.'.
+                ] ifFalse:[
+                    sock buffered:false.
+                    Transcript showCR:'server: got it'.
+                    'can now do transfer via sock'.
+                    Transcript showCR:'read'.
+                    Transcript showCR:('got: ' , sock nextLine).
+
+                    Transcript showCR:'close'.
+                    sock close
+                ].
+                connectSock close.
+            ]
+        ]
+                                                                        [exEnd]
 
 
     example (connect to above server and send some data):
-									[exBegin]
-	|sock|
-
-	sock := Socket newTCPclientToHost:(OperatingSystem getHostName) port:9998.
-	sock isNil ifTrue:[
-	    Transcript showCR:'nope'
-	] ifFalse:[
-	    sock buffered:false.
-	    Transcript showCR:'client: got it'.
-	    'can now do transfer via sock'.
-	    Transcript showCR:'sending <hello>'.
-	    sock nextPutLine:'hello'.
-	    sock close
-	]
-									[exEnd]
+                                                                        [exBegin]
+        |sock|
+
+        sock := Socket newTCPclientToHost:'localhost' port:9998.
+        sock isNil ifTrue:[
+            Transcript showCR:'nope'
+        ] ifFalse:[
+            sock buffered:false.
+            Transcript showCR:'client: got it'.
+            'can now do transfer via sock'.
+            Transcript showCR:'sending <hello>'.
+            sock nextPutLine:'hello'.
+            sock close
+        ]
+                                                                        [exEnd]
 
     example: UNIX domain socket (await connection from a client and read some data):
 
-	|connectSock sock|
-
-	'/tmp/ud_socket' asFilename remove.
-	connectSock := Socket newUNIXserverAt:'/tmp/ud_socket'.
-	connectSock isNil ifTrue:[
-	    Transcript showCR:'socket setup failed.'.
-	] ifFalse:[
-	    Transcript showCR:'listen ..'.
-	    (connectSock listenFor:5) ifFalse:[
-		Transcript showCR:'listen failed.'.
-	    ] ifTrue:[
-		Transcript showCR:'wait'.
-		connectSock buffered:false.
-		connectSock readWait.
-		Transcript showCR:'accept'.
-		sock := connectSock accept.
-		sock isNil ifTrue:[
-		    Transcript showCR:'accept failed.'.
-		] ifFalse:[
-		    sock buffered:false.
-		    Transcript showCR:'server: got it'.
-		    'can now do transfer via sock'.
-		    Transcript showCR:'read'.
-		    Transcript showCR:('got: ' , sock nextLine).
-
-		    Transcript showCR:'close'.
-		    sock close
-		].
-		connectSock close.
-	    ]
-	]
+        |connectSock sock|
+
+        '/tmp/ud_socket' asFilename remove.
+        connectSock := Socket newUNIXserverAt:'/tmp/ud_socket'.
+        connectSock isNil ifTrue:[
+            Transcript showCR:'socket setup failed.'.
+        ] ifFalse:[
+            Transcript showCR:'listen ..'.
+            (connectSock listenFor:5) ifFalse:[
+                Transcript showCR:'listen failed.'.
+            ] ifTrue:[
+                Transcript showCR:'wait'.
+                connectSock buffered:false.
+                connectSock readWait.
+                Transcript showCR:'accept'.
+                sock := connectSock accept.
+                sock isNil ifTrue:[
+                    Transcript showCR:'accept failed.'.
+                ] ifFalse:[
+                    sock buffered:false.
+                    Transcript showCR:'server: got it'.
+                    'can now do transfer via sock'.
+                    Transcript showCR:'read'.
+                    Transcript showCR:('got: ' , sock nextLine).
+
+                    Transcript showCR:'close'.
+                    sock close
+                ].
+                connectSock close.
+            ]
+        ]
 
 
     example (connect to above server and send some data;
-	     Notice, this fails, if above server code is executed in the same ST/X image
-		     (at least on LINUX), since the OS does not correctly handle
-		     a connect from within an interrupted accept system call
-		     On SGI's SVR4, this works ok
-									[exBegin]
-	|sock|
-
-	sock := Socket newUNIXclientTo:'/tmp/ud_socket'.
-	sock isNil ifTrue:[
-	    Transcript showCR:'nope'
-	] ifFalse:[
-	    sock buffered:false.
-	    Transcript showCR:'client: got it'.
-	    'can now do transfer via sock'.
-	    Transcript showCR:'sending <hello>'.
-	    sock nextPutLine:'hello'.
-	    sock close
-	]
-									[exEnd]
+             Notice, this fails, if above server code is executed in the same ST/X image
+                     (at least on LINUX), since the OS does not correctly handle
+                     a connect from within an interrupted accept system call
+                     On SGI's SVR4, this works ok
+                                                                        [exBegin]
+        |sock|
+
+        sock := Socket newUNIXclientTo:'/tmp/ud_socket'.
+        sock isNil ifTrue:[
+            Transcript showCR:'nope'
+        ] ifFalse:[
+            sock buffered:false.
+            Transcript showCR:'client: got it'.
+            'can now do transfer via sock'.
+            Transcript showCR:'sending <hello>'.
+            sock nextPutLine:'hello'.
+            sock close
+        ]
+                                                                        [exEnd]
 
 
     example (UDP await packet from a client and read some data):
-									[exBegin]
-	|udpSock sock addr n dataBuffer|
-
-	udpSock := Socket newUDPserverAtPort:9999.
-	udpSock isNil ifTrue:[
-	    Transcript showCR:'socket setup failed.'.
-	] ifFalse:[
-	    Transcript showCR:'wait'.
-	    udpSock readWait.
-
-	    addr := IPSocketAddress new.
-	    dataBuffer := ByteArray new:1000.
-	    n := udpSock receiveFrom:addr buffer:dataBuffer start:1 for:dataBuffer size.
-	    n > 0 ifTrue:[
-		Transcript showCR:('got: ' , n printString , 'bytes  from ' , addr printString).
-		Transcript showCR:('data: ' , (dataBuffer copyTo:n) printString).
-	    ] ifFalse:[
-		Transcript showCR:'read failed'.
-	    ].
-
-	    Transcript showCR:'close'.
-	    udpSock close
-	]
-									[exEnd]
+                                                                        [exBegin]
+        |udpSock sock addr n dataBuffer|
+
+        udpSock := Socket newUDPserverAtPort:9999.
+        udpSock isNil ifTrue:[
+            Transcript showCR:'socket setup failed.'.
+        ] ifFalse:[
+            Transcript showCR:'wait'.
+            udpSock readWait.
+
+            addr := IPSocketAddress new.
+            dataBuffer := ByteArray new:1000.
+            n := udpSock receiveFrom:addr buffer:dataBuffer start:1 for:dataBuffer size.
+            n > 0 ifTrue:[
+                Transcript showCR:('got: ' , n printString , 'bytes  from ' , addr printString).
+                Transcript showCR:('data: ' , (dataBuffer copyTo:n) printString).
+            ] ifFalse:[
+                Transcript showCR:'read failed'.
+            ].
+
+            Transcript showCR:'close'.
+            udpSock close
+        ]
+                                                                        [exEnd]
     example (connect to above UDP server and send some data;
-									[exBegin]
-	|sock|
-
-	sock := Socket newUDP.
-	sock isNil ifTrue:[
-	    Transcript showCR:'nope'
-	] ifFalse:[
-	    sock sendTo:(IPSocketAddress new hostName:'localhost' port:9999) buffer:'hello world'.
-	    sock close
-	]
-									[exEnd]
+                                                                        [exBegin]
+        |sock|
+
+        sock := Socket newUDP.
+        sock isNil ifTrue:[
+            Transcript showCR:'nope'
+        ] ifFalse:[
+            sock sendTo:(IPSocketAddress new hostName:'localhost' port:9999) buffer:'hello world'.
+            sock close
+        ]
+                                                                        [exEnd]
 
     example: pingWalk (try to ping hosts on the local network)
-									[exBegin]
-	|myName myAddress list top hosts walkProcess port|
-
-	myName := OperatingSystem getHostName.
-	myAddress := Socket ipAddressOfHost:myName.
-
-	port := Socket portOfService:'echo'.
-	port isNil ifTrue:[
-	    self error:'dont know echo port'.
-	    ^ self
-	].
-
-	top := StandardSystemView new.
-	top label:'PING net walk'.
-
-	list := ScrollableView for:ListView in:top.
-	list origin:0.0@0.0 corner:1.0@1.0.
-
-	top openAndWait.
-
-	walkProcess := [
-	    |l low hi direction tryHostID dottedName hostName conn addr|
-
-	    l := SortedCollection new.
-
-	    ' only works with type C-net
-	      the code below could simply do 1 to:254 do:[:hostID }
-	      but, to probe likely hosts earlier, the probing is done
-	      ping-pong like around my ip-address (assuming, that other machines
-	      have numbers around my own)'.
-
-	    low := hi := (myAddress at:4).
-	    direction := 1.
-
-	    [low > 0 or:[hi < 255]] whileTrue:[
-		direction > 0 ifTrue:[
-		    hi := hi + 1.
-		    tryHostID := hi.
-		    direction := -1.
-		] ifFalse:[
-		    low := low - 1.
-		    tryHostID := low.
-		    direction := 1.
-		].
-		(tryHostID between:1 and:254) ifTrue:[
-		    dottedName := (myAddress at:1) printString
-				  , '.' , (myAddress at:2) printString
-				  , '.' , (myAddress at:3) printString
-				  , '.' , tryHostID printString.
-
-		    top label:'PING net walk - trying ' , dottedName.
-
-		    top windowGroup withCursor:Cursor wait do:[
-			conn := Socket newTCPclientToHost:dottedName port:port withTimeout:1000.
-			conn notNil ifTrue:[
-			    addr := Socket ipAddressOfHost:dottedName.
-			    hostName := Socket hostWithIpAddress:addr.
-			    hostName isNil ifTrue:[
-				hostName :='?'
-			    ].
-			    l add:(dottedName paddedTo:15 with:Character space)
-				   , ' '
-				   , (hostName paddedTo:15 with:Character space)
-				   , ' up & reachable'.
-			    list list:l.
-			    conn close.
-			]
-		    ].
-		].
-	    ].
-	    top label:'PING reachable hosts'.
-	] forkAt:(Processor userBackgroundPriority).
-	walkProcess name:'ping net walker'.
-									[exEnd]
-
-
-	This example creates a simple UDP server that accepts
-	single packets from anybody and broadcasts them to all
-	clients that have connected so far.
-
-									[exBegin]
-	| socket address buffer msgSize clients |
-	clients := Set new.
-	address := IPSocketAddress new.
-	buffer := String new: 1024.
-
-	socket := self newUDPserverAtPort: 6666.
-
-	Transcript showCR: 'server starting'.
-
-	[
-	    [true] whileTrue: [
-		(socket readWaitWithTimeoutMs: 200) ifFalse: [
-		    msgSize := socket
-			    receiveFrom: address
-			    buffer: buffer
-			    start: 1
-			    for: buffer size.
-
-		    clients add: address copy.
-		    clients do: [ :clientAddress |
-			    socket
-				    sendTo: clientAddress
-				    buffer: buffer
-				    start: 1
-				    for: msgSize]]
-	    ]
-	] ensure:[
-	    Transcript showCR: 'server shutting down'.
-	    socket close
-	]
-									[exEnd]
+                                                                        [exBegin]
+        |myName myAddress list top hosts walkProcess port|
+
+        myName := OperatingSystem getHostName.
+        myAddress := Socket ipAddressOfHost:myName.
+
+        port := Socket portOfService:'echo'.
+        port isNil ifTrue:[
+            self error:'dont know echo port'.
+            ^ self
+        ].
+
+        top := StandardSystemView new.
+        top label:'PING net walk'.
+
+        list := ScrollableView for:ListView in:top.
+        list origin:0.0@0.0 corner:1.0@1.0.
+
+        top openAndWait.
+
+        walkProcess := [
+            |l low hi direction tryHostID dottedName hostName conn addr|
+
+            l := SortedCollection new.
+
+            ' only works with type C-net
+              the code below could simply do 1 to:254 do:[:hostID }
+              but, to probe likely hosts earlier, the probing is done
+              ping-pong like around my ip-address (assuming, that other machines
+              have numbers around my own)'.
+
+            low := hi := (myAddress at:4).
+            direction := 1.
+
+            [low > 0 or:[hi < 255]] whileTrue:[
+                direction > 0 ifTrue:[
+                    hi := hi + 1.
+                    tryHostID := hi.
+                    direction := -1.
+                ] ifFalse:[
+                    low := low - 1.
+                    tryHostID := low.
+                    direction := 1.
+                ].
+                (tryHostID between:1 and:254) ifTrue:[
+                    dottedName := (myAddress at:1) printString
+                                  , '.' , (myAddress at:2) printString
+                                  , '.' , (myAddress at:3) printString
+                                  , '.' , tryHostID printString.
+
+                    top label:'PING net walk - trying ' , dottedName.
+
+                    top windowGroup withCursor:Cursor wait do:[
+                        conn := Socket newTCPclientToHost:dottedName port:port withTimeout:1000.
+                        conn notNil ifTrue:[
+                            addr := Socket ipAddressOfHost:dottedName.
+                            hostName := Socket hostWithIpAddress:addr.
+                            hostName isNil ifTrue:[
+                                hostName :='?'
+                            ].
+                            l add:(dottedName paddedTo:15 with:Character space)
+                                   , ' '
+                                   , (hostName paddedTo:15 with:Character space)
+                                   , ' up & reachable'.
+                            list list:l.
+                            conn close.
+                        ]
+                    ].
+                ].
+            ].
+            top label:'PING reachable hosts'.
+        ] forkAt:(Processor userBackgroundPriority).
+        walkProcess name:'ping net walker'.
+                                                                        [exEnd]
+
+
+        This example creates a simple UDP server that accepts
+        single packets from anybody and broadcasts them to all
+        clients that have connected so far.
+
+                                                                        [exBegin]
+        | socket address buffer msgSize clients |
+        clients := Set new.
+        address := IPSocketAddress new.
+        buffer := String new: 1024.
+
+        socket := self newUDPserverAtPort: 6666.
+
+        Transcript showCR: 'server starting'.
+
+        [
+            [true] whileTrue: [
+                (socket readWaitWithTimeoutMs: 200) ifFalse: [
+                    msgSize := socket
+                            receiveFrom: address
+                            buffer: buffer
+                            start: 1
+                            for: buffer size.
+
+                    clients add: address copy.
+                    clients do: [ :clientAddress |
+                            socket
+                                    sendTo: clientAddress
+                                    buffer: buffer
+                                    start: 1
+                                    for: msgSize]]
+            ]
+        ] ensure:[
+            Transcript showCR: 'server shutting down'.
+            socket close
+        ]
+                                                                        [exEnd]
 
    send a datagram to above server:
-									[exBegin]
-
-	| socket address buffer host msg |
-
-	host := Dialog
-		request: 'What is the name of the server''s host?'
-		initialAnswer: 'localhost'.
-
-	socket := self newUDP.
-
-	address := IPSocketAddress hostName: host port: 6666.
-
-	buffer := ByteArray new: 1000.
-	[
-	    [(msg := Dialog request: 'Say something') isEmpty] whileFalse:[
-		| replySize stream |
-
-		socket writeWait.
-		stream := buffer writeStream.
-		stream nextPutAll: msg.
-		socket sendTo:address buffer:buffer start:1 for:stream position.
-		socket readWait.
-
-		replySize := socket receiveFrom:address buffer:buffer.
-		replySize > 0 ifTrue: [
-		    Transcript cr; nextPutAll: 'Server acknowledged: '.
-		    Transcript show: ((buffer copyFrom: 1 to: replySize) asString)
-		]
-	    ]
-	] ensure: [socket close].
-	Transcript cr
-									[exEnd]
+                                                                        [exBegin]
+
+        | socket address buffer host msg |
+
+        host := Dialog
+                request: 'What is the name of the server''s host?'
+                initialAnswer: 'localhost'.
+
+        socket := self newUDP.
+
+        address := IPSocketAddress hostName: host port: 6666.
+
+        buffer := ByteArray new: 1000.
+        [
+            [(msg := Dialog request: 'Say something') isEmpty] whileFalse:[
+                | replySize stream |
+
+                socket writeWait.
+                stream := buffer writeStream.
+                stream nextPutAll: msg.
+                socket sendTo:address buffer:buffer start:1 for:stream position.
+                socket readWait.
+
+                replySize := socket receiveFrom:address buffer:buffer.
+                replySize > 0 ifTrue: [
+                    Transcript cr; nextPutAll: 'Server acknowledged: '.
+                    Transcript show: ((buffer copyFrom: 1 to: replySize) asString)
+                ]
+            ]
+        ] ensure: [socket close].
+        Transcript cr
+                                                                        [exEnd]
 
 
    loopBack:
-									[exBegin]
-
-	|readerTask readingSocket writingSocket|
-
-	readingSocket := self newTCPserverAtPort:9999.
-	readerTask :=
-	    [
-		|connection|
-
-		readingSocket listenFor:1.
-		connection := readingSocket accept.
-		readingSocket close.
-		[connection atEnd] whileFalse:[
-		    Transcript showCR:(connection nextLine).
-		].
-		connection close.
-	    ] fork.
-
-	Delay waitForSeconds:1.
-	writingSocket := self newTCPclientToHost:(OperatingSystem getHostName) port:9999.
-	writingSocket nextPutLine:'Hello'.
-	writingSocket nextPutLine:'World'.
-	writingSocket close.
-									[exEnd]
+                                                                        [exBegin]
+
+        |readerTask readingSocket writingSocket|
+
+        readingSocket := self newTCPserverAtPort:9999.
+        readerTask :=
+            [
+                |connection|
+
+                readingSocket listenFor:1.
+                connection := readingSocket accept.
+                readingSocket close.
+                [connection atEnd] whileFalse:[
+                    Transcript showCR:(connection nextLine).
+                ].
+                connection close.
+            ] fork.
+
+        Delay waitForSeconds:1.
+        writingSocket := self newTCPclientToHost:'localhost' port:9999.
+        writingSocket nextPutLine:'Hello'.
+        writingSocket nextPutLine:'World'.
+        writingSocket close.
+                                                                        [exEnd]
 "
 ! !
 
@@ -1958,8 +1959,8 @@
 shutDownOutput
     "shutDown the output side of the socket.
      Any write to the socket will signal end-of-file from now on.
-     The other side will get a end-of-file condition,
-     after the last buffered data has been read"
+     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."
 
     self shutdown:1.
 ! !
@@ -2532,18 +2533,17 @@
 
     |domainClass addr|
 
-    domainClass := self class socketAddressClassForDomain:domain.
-    domainClass isNil ifTrue:[
-	^ self error:'invalid (unsupported) domain'.
-    ].
-
     (anAddressBuffer isKindOf:SocketAddress) ifTrue:[
-	addr := anAddressBuffer.
+        addr := anAddressBuffer.
     ] ifFalse:[
-	anAddressBuffer isByteArray ifFalse:[
-	    ^ self error:'bad socketAddress argument'
-	].
-	addr := domainClass hostAddress:anAddressBuffer.
+        anAddressBuffer isByteArray ifFalse:[
+            ^ self error:'bad socketAddress argument'
+        ].
+        domainClass := self class socketAddressClassForDomain:domain.
+        domainClass isNil ifTrue:[
+            ^ self error:'invalid (unsupported) domain'.
+        ].
+        addr := domainClass hostAddress:anAddressBuffer.
     ].
 %{
 #ifndef NO_SOCKET
@@ -2552,82 +2552,82 @@
     if ((fp != nil)
      && __isSmallInteger(startIndex)
      && __isSmallInteger(nBytes)) {
-	SOCKET sock;
-	int objSize;
-	struct sockaddr *sockaddr_ptr;
-	union sockaddr_u sa;
-	int alen = 0;
-	int sockAddrOffs, sockaddr_size;
-	int n;
-	char *extPtr;
-	int _flags = 0;
-	int offs;
-	unsigned long norder;
-	unsigned char *buffer;
-	unsigned char *allocatedBuffer = NULL;
-
-	_flags = __longIntVal(flags);
-	sock = SOCKET_FROM_FILE_OBJECT(fp);
-
-	if (! __isBytes(addr)) {
-	    sockaddr_size = 0;
-	    sockaddr_ptr = (struct sockaddr *)0;
-	} else {
-	    int nIndex;
-	    OBJ cls;
-
-	    sockAddrOffs = 0;
-	    if ((cls = __qClass(addr)) != @global(ByteArray))
-		sockAddrOffs += __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
-	    nIndex = __qSize(addr) - OHDR_SIZE;
-	    sockaddr_size = nIndex - sockAddrOffs;
-	    if (sockaddr_size > sizeof(sa)) {
-		console_fprintf(stderr, "Socket [warning]: bad socketAddr\n");
-		goto bad;
-	    }
-	    bcopy((__byteArrayVal(addr) + sockAddrOffs), &sa, sockaddr_size);
-	    sockaddr_ptr = (struct sockaddr *)(&sa);
-	}
-
-	if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad;
-	if (__isSmallInteger(nBytes)) {
-	    if (__intVal(nBytes) < objSize) {
-		objSize = __intVal(nBytes);
-	    }
-	}
+        SOCKET sock;
+        int objSize;
+        struct sockaddr *sockaddr_ptr;
+        union sockaddr_u sa;
+        int alen = 0;
+        int sockAddrOffs, sockaddr_size;
+        int n;
+        char *extPtr;
+        int _flags = 0;
+        int offs;
+        unsigned long norder;
+        unsigned char *buffer;
+        unsigned char *allocatedBuffer = NULL;
+
+        _flags = __longIntVal(flags);
+        sock = SOCKET_FROM_FILE_OBJECT(fp);
+
+        if (! __isBytes(addr)) {
+            sockaddr_size = 0;
+            sockaddr_ptr = (struct sockaddr *)0;
+        } else {
+            int nIndex;
+            OBJ cls;
+
+            sockAddrOffs = 0;
+            if ((cls = __qClass(addr)) != @global(ByteArray))
+                sockAddrOffs += __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
+            nIndex = __qSize(addr) - OHDR_SIZE;
+            sockaddr_size = nIndex - sockAddrOffs;
+            if (sockaddr_size > sizeof(sa)) {
+                console_fprintf(stderr, "Socket [warning]: bad socketAddr\n");
+                goto bad;
+            }
+            bcopy((__byteArrayVal(addr) + sockAddrOffs), &sa, sockaddr_size);
+            sockaddr_ptr = (struct sockaddr *)(&sa);
+        }
+
+        if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad;
+        if (__isSmallInteger(nBytes)) {
+            if (__intVal(nBytes) < objSize) {
+                objSize = __intVal(nBytes);
+            }
+        }
 
 #ifdef DO_WRAP_CALLS
-	if (extPtr) {
-	    buffer = extPtr + offs;
-	} else {
-	    allocatedBuffer = buffer = (char *)malloc(objSize);
-	    bcopy((char *)__InstPtr(aDataBuffer) + offs, allocatedBuffer, objSize);
-	}
-
-	do {
-	    __threadErrno = 0;
-	    n = STX_WSA_NOINT_CALL6("sendto", sendto, sock, buffer, objSize, _flags, sockaddr_ptr, sockaddr_size);
-	} while ((n < 0) && (__threadErrno == EINTR));
-
-	if (allocatedBuffer) {
-	    free(allocatedBuffer);
-	}
+        if (extPtr) {
+            buffer = extPtr + offs;
+        } else {
+            allocatedBuffer = buffer = (char *)malloc(objSize);
+            bcopy((char *)__InstPtr(aDataBuffer) + offs, allocatedBuffer, objSize);
+        }
+
+        do {
+            __threadErrno = 0;
+            n = STX_WSA_NOINT_CALL6("sendto", sendto, sock, buffer, objSize, _flags, sockaddr_ptr, sockaddr_size);
+        } while ((n < 0) && (__threadErrno == EINTR));
+
+        if (allocatedBuffer) {
+            free(allocatedBuffer);
+        }
 #else
-	__BEGIN_INTERRUPTABLE__
-	do {
-	    if (extPtr) {
-		n = sendto(sock, extPtr + offs, objSize, _flags, sockaddr_ptr, sockaddr_size);
-	    } else {
-		n = sendto(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, _flags, sockaddr_ptr, sockaddr_size);
-	    }
-	} while ((n < 0) && (errno == EINTR));
-	__END_INTERRUPTABLE__
+        __BEGIN_INTERRUPTABLE__
+        do {
+            if (extPtr) {
+                n = sendto(sock, extPtr + offs, objSize, _flags, sockaddr_ptr, sockaddr_size);
+            } else {
+                n = sendto(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, _flags, sockaddr_ptr, sockaddr_size);
+            }
+        } while ((n < 0) && (errno == EINTR));
+        __END_INTERRUPTABLE__
 #endif
 
-	if (n < 0) {
-	    __INST(lastErrorNumber) = __MKSMALLINT(errno);
-	}
-	RETURN (__MKSMALLINT(n));
+        if (n < 0) {
+            __INST(lastErrorNumber) = __MKSMALLINT(errno);
+        }
+        RETURN (__MKSMALLINT(n));
     }
 #endif
 bad: ;
@@ -2652,50 +2652,66 @@
 
     t = __INST(handle);
     if (t != nil) {
-	FILE *fp;
-	SOCKET sock;
-	int fd;
-
-	__INST(handle) = nil;
-	fp = __FILEVal(t);
-	fd = fileno(fp);
-	sock = SOCKET_FROM_FD(fd);
+        FILE *fp;
+        SOCKET sock;
+        int fd;
+
+        __INST(handle) = nil;
+        fp = __FILEVal(t);
+        fd = fileno(fp);
+        sock = SOCKET_FROM_FD(fd);
 
 # ifdef DO_WRAP_CALLS
-	{
-	  int ret;
-	  /*__setWrapCallDebugging(1,1); */
-
-	  do {
-	    __threadErrno = 0;
-	    ret = STX_C_NOINT_CALL1("fclose", fclose, fp);
-	  } while ((ret < 0) && (__threadErrno == EINTR));
+        {
+          int ret;
+          /*__setWrapCallDebugging(1,1); */
+
+          if (__INST(buffered) == true){
+              /* do a fflush() first, so that fclose() doesn't block
+               * we suspect, that EINTR causes problems in fclose()
+               */ 
+              do {
+                  __threadErrno = 0;
+                  rslt = __STX_C_CALL1("fflush", fflush, f);
+              } while((rslt < 0) && (__threadErrno == EINTR));
+          }
+
+#  if if defined(WIN32) && defined(CLOSESOCKET_BEFORE_FCLOSE)
+          DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock));
+          closesocket(sock);
+#  endif
+          do {
+            __threadErrno = 0;
+            ret = STX_C_NOINT_CALL1("fclose", fclose, fp);
+          } while ((ret < 0) && (__threadErrno == EINTR));
 
 #  if defined(WIN32) && defined(CLOSESOCKET_AFTER_FCLOSE)
-	  do {
-	    __threadErrno = 0;
-	    ret = STX_WSA_NOINT_CALL1("closesocket", closesocket, sock);
-	  } while ((ret < 0) && (__threadErrno == EINTR));
+          do {
+            __threadErrno = 0;
+            ret = STX_WSA_NOINT_CALL1("closesocket", closesocket, sock);
+          } while ((ret < 0) && (__threadErrno == EINTR));
 #  endif
-	  /*__setWrapCallDebugging(1,0);*/
-	}
+          /*__setWrapCallDebugging(1,0);*/
+        }
 # else /* !DO_WRAP_CALLS */
 
-	DBGFPRINTF((stderr, "SOCKET: fflush %x (%d %d)\n", fp, fileno(fp), sock));
-	fflush(fp);
+        if (__INST(buffered) == true){
+            DBGFPRINTF((stderr, "SOCKET: fflush %x (%d %d)\n", fp, fileno(fp), sock));
+            fflush(fp);
+        }
 
 #  if defined(CLOSESOCKET_BEFORE_FCLOSE)
-	DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock));
-	closesocket(sock);
+        DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock));
+        closesocket(sock);
 #  endif
-	if ((@global(FileOpenTrace) == true) || __debugging__) {
-	    console_fprintf(stderr, "SOCKET: fclose %x (%d %d)\n", fp, fileno(fp), sock);
-	}
-	fclose(fp);
+        if ((@global(FileOpenTrace) == true) || __debugging__) {
+            console_fprintf(stderr, "SOCKET: fclose %x (%d %d)\n", fp, fileno(fp), sock);
+        }
+        fclose(fp);
 
 #  if defined(CLOSESOCKET_AFTER_FCLOSE)
-	DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock));
-	closesocket(sock);
+        DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock));
+        closesocket(sock);
 #  endif
 
 # endif /* !DO_WRAP_CALLS */
@@ -3223,37 +3239,46 @@
     ].
 !
 
-shutdown: howNum
+shutdown:howNum
     "shutDown the socket - inform it that no more I/O will be performed.
-	 0 - read side   (no further reads)
-	 1 - write side  (no further writes)
-	 2 - both        (no further I/O at all)
-     shutDown:2
-	discards any pending data
-	(as opposed to close, which might wait until data is delivered as set by LINGER)"
+         0 - read side   (no further reads)
+             the tcp receive window is closed, so the peer cannot send more data.
+         1 - write side  (no further writes)
+             first, all queued data will be delivered to the peer.
+             Then, an orderly release (TCP FIN) is sent to signal the peer,
+             that we will not send more data.
+         2 - both read side and write side."
 
 %{
 #ifndef NO_SOCKET
-
-    OBJ fp;
-
-    fp = __INST(handle);
-    if ((fp != nil) && __isSmallInteger(howNum)) {
-	SOCKET sock;
-	int ret;
-
-	sock = SOCKET_FROM_FILE_OBJECT(fp);
+    OBJ __handle = __INST(handle);
+    if ((__handle != nil) && __isSmallInteger(howNum)) {
+        FILE *fp = __FILEVal(__handle);
+        SOCKET sock = SOCKET_FROM_FILE(fp);
+        int how = __intVal(howNum);
+        int ret;
+
 # ifdef DO_WRAP_CALLS
-	do {
-	    __threadErrno = 0;
-	    DBGFPRINTF((stderr, "SOCKET: shutDown...\n"));
-	    ret = STX_WSA_NOINT_CALL2("shutdown", shutdown, sock, __intVal(howNum));
-	    DBGFPRINTF((stderr, "SOCKET: shutDown -> %d (%d)\n", ret, __threadErrno));
-	} while ((ret < 0) && (__threadErrno == EINTR));
+        if (how > 0 && __INST(buffered) == true) {
+            // do a fflush() first, so that fclose() doesn't block
+            do {
+                __threadErrno = 0;
+                rslt = __STX_C_CALL1("fflush", fflush, fp);
+            } while((rslt < 0) && (__threadErrno == EINTR));
+        }
+        do {
+            __threadErrno = 0;
+            DBGFPRINTF((stderr, "SOCKET: shutDown...\n"));
+            ret = STX_WSA_NOINT_CALL2("shutdown", shutdown, sock, how);
+            DBGFPRINTF((stderr, "SOCKET: shutDown -> %d (%d)\n", ret, __threadErrno));
+        } while ((ret < 0) && (__threadErrno == EINTR));
 # else
-	__BEGIN_INTERRUPTABLE__
-	shutdown(sock, __intVal(howNum));
-	__END_INTERRUPTABLE__
+        if (how > 0 && __INST(buffered) == true) {
+            fflush(fp);
+        }
+        __BEGIN_INTERRUPTABLE__
+        shutdown(sock, how);
+        __END_INTERRUPTABLE__
 # endif
     }
 #endif
@@ -4017,9 +4042,9 @@
 !Socket class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.269 2012-09-03 20:23:42 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.270 2012-10-08 07:45:43 stefan Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.269 2012-09-03 20:23:42 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.270 2012-10-08 07:45:43 stefan Exp $'
 ! !