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