[Pkg] The Trunk: Network-dtl.123.mcz

commits at source.squeak.org commits at source.squeak.org
Wed Jun 20 00:16:54 UTC 2012


David T. Lewis uploaded a new version of Network to project The Trunk:
http://source.squeak.org/trunk/Network-dtl.123.mcz

==================== Summary ====================

Name: Network-dtl.123
Author: dtl
Time: 4 June 2012, 10:20:03.7 pm
UUID: 5d13b001-10bb-4300-a066-e951cfe68c50
Ancestors: Network-ul.122

Merge Network-ul.100 (Network changes from the EToys repository) from inbox.

Make the network tests run with no new failures. Two failures were present on my unix system for #testSendTimeout and #testSocketReuse. These are preexisting failures unrelated to this update (probably Linux platform related).

NetNameResolver may be set to UseOldNetwork = false to partially restore previous behavior, as may be required for compatibility with external packages. Test results are identical for either mode.

To the extent possible, socket addresses are represented as instances of SocketAddress when UseOldNetwork is false, and as ByteArray otherwise. In particular, Socket>>localAddress and Socket>>remoteAddress now answer a SocketAddress unless UseOldNetwork is set false. This is a possible source of problems for external packages.

Some primitives expect IPV4 byte array arguments in all cases, possibly some future updates will be in order for these.

Implement ByteArray>>asSocketAddress to use NetNameResolver and primitives to create a SocketAddress for the old style byte array. Implement SocketAddress>>asByteArray for the reverse conversion, assuming that the socket address is IPV4.

Etoys note: A SocketAddress may be initialized only through primitive calls. Therefore creating a new instance from a ByteArray is invalid. The #asSocketAddress implementation in the Etoys image should be updated accordingly.

=============== Diff against Network-ul.122 ===============

Item was changed:
  Object subclass: #ConnectionQueue
  	instanceVariableNames: 'portNumber maxQueueLength connections accessSema socket process'
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'Network-Kernel'!
  
  !ConnectionQueue commentStamp: '<historical>' prior: 0!
  A ConnectionQueue listens on a given port number and collects a queue of client connections. In order to handle state changes quickly, a ConnectionQueue has its own process that: (a) tries to keep a socket listening on the port whenever the queue isn't already full of connections and (b) prunes stale connections out of the queue to make room for fresh ones.
+ 
+ The portNumber can be initialized to a collection, in which case all ports will be probed to create a listening socket. Once successfull, the portNumber is set to the chosen port.!
- !

Item was added:
+ ----- Method: ConnectionQueue>>createListeningSocketWithBacklog: (in category 'private') -----
+ createListeningSocketWithBacklog: aNumber
+ 	| addressInfo sock |
+ 	self portNumbers do: [:trialportNumber | 
+ 		addressInfo := SocketAddressInformation
+ 			forHost: ''
+ 			service: trialportNumber asString
+ 			flags: SocketAddressInformation passiveFlag
+ 			addressFamily: SocketAddressInformation addressFamilyINET4
+ 			socketType: SocketAddressInformation socketTypeStream
+ 			protocol: SocketAddressInformation protocolTCP.
+ 		sock := [addressInfo first listenWithBacklog: aNumber] ifError: [nil].
+ 		sock ifNotNil: [
+ 			portNumber := trialportNumber.
+ 			^ sock]].
+ 	^ nil!

Item was changed:
  ----- Method: ConnectionQueue>>listenLoop (in category 'private') -----
  listenLoop
  	"Private!! This loop is run in a separate process. It will establish up to maxQueueLength connections on the given port."
  	"Details: When out of sockets or queue is full, retry more frequently, since a socket may become available, space may open in the queue, or a previously queued connection may be aborted by the client, making it available for a fresh connection."
  	"Note: If the machine is disconnected from the network while the server is running, the currently waiting socket will go from 'isWaitingForConnection' to 'unconnected', and attempts to create new sockets will fail. When this happens, delete the broken socket and keep trying to create a socket in case the network connection is re-established. Connecting and disconnecting was tested under PPP on Mac system 8.1. It is not if this will work on other platforms."
  
  
  	| newConnection |
- 
- 	socket := Socket newTCP.
  	"We'll accept four simultanous connections at the same time"
+ 	NetNameResolver useOldNetwork
+ 		ifFalse: [ socket := self createListeningSocketWithBacklog: 4 ]
+ 		ifTrue: [
+ 			socket := Socket newTCP.
+ 			socket listenOn: portNumber backlogSize: 4 ].
- 	socket listenOn: portNumber backlogSize: 4.
  	"If the listener is not valid then the we cannot use the
  	BSD style accept() mechanism."
  	socket isValid ifFalse: [^self oldStyleListenLoop].
  	[
  		socket isValid ifFalse: [
  			"socket has stopped listening for some reason"
  			socket destroy.
  			(Delay forMilliseconds: 10) wait.
  			^self listenLoop ].
  		newConnection := socket 
  			waitForAcceptFor: 10
  			ifTimedOut: [ nil ].
  		(newConnection notNil and: [newConnection isConnected]) ifTrue: [
  			accessSema critical: [connections addLast: newConnection.].
  			newConnection := nil.
  			self changed].
  		self pruneStaleConnections] repeat!

Item was changed:
  ----- Method: ConnectionQueue>>oldStyleListenLoop (in category 'private') -----
  oldStyleListenLoop
  	"Private!! This loop is run in a separate process. It will establish up to maxQueueLength connections on the given port."
  	"Details: When out of sockets or queue is full, retry more frequently, since a socket may become available, space may open in the queue, or a previously queued connection may be aborted by the client, making it available for a fresh connection."
  	"Note: If the machine is disconnected from the network while the server is running, the currently waiting socket will go from 'isWaitingForConnection' to 'unconnected', and attempts to create new sockets will fail. When this happens, delete the broken socket and keep trying to create a socket in case the network connection is re-established. Connecting and disconnecting was tested under PPP on Mac system 8.1. It is not if this will work on other platforms."
  
  	[
  		((socket == nil) and: [connections size < maxQueueLength]) ifTrue: [
  			"try to create a new socket for listening"
  			socket := Socket createIfFail: [nil]].
  
  		socket == nil
  			ifTrue: [(Delay forMilliseconds: 100) wait]
  			ifFalse: [
  				socket isUnconnected ifTrue: [socket listenOn: portNumber].
  				socket 
  					waitForConnectionFor: 10
  					ifTimedOut: [
  						socket isConnected
  							ifTrue: [  "connection established"
  								accessSema critical: [connections addLast: socket].
  								socket := nil]
  							ifFalse: [
  								socket isWaitingForConnection
  									ifFalse: [socket destroy. socket := nil]]]].  "broken socket; start over"
+ 		self pruneStaleConnections] repeat
+ !
- 		self pruneStaleConnections] repeat!

Item was added:
+ ----- Method: ConnectionQueue>>portNumber (in category 'public') -----
+ portNumber
+ 	^ portNumber isCollection
+ 		ifTrue: [portNumber first]
+ 		ifFalse: [portNumber]!

Item was added:
+ ----- Method: ConnectionQueue>>portNumberOrNil (in category 'public') -----
+ portNumberOrNil
+ 	"Answer nil while actual port has not been established"
+ 	^ portNumber isCollection
+ 		ifFalse: [portNumber]!

Item was added:
+ ----- Method: ConnectionQueue>>portNumbers (in category 'public') -----
+ portNumbers
+ 	^ portNumber isCollection
+ 		ifTrue: [portNumber]
+ 		ifFalse: [{portNumber}]!

Item was changed:
  ----- Method: HTTPSocket class>>httpShowPage: (in category 'get the page') -----
  httpShowPage: url
  	"Display the exact contents of the given URL as text. See examples in httpGet:"
  
  	| doc |
  	doc := (self httpGet: url accept: 'application/octet-stream') contents.
+ 	doc size = 0 ifTrue: [^ self error: 'Document could not be fetched' translated].
- 	doc size = 0 ifTrue: [^ self error: 'Document could not be fetched'].
  	(StringHolder new contents: doc) openLabel: url.
  !

Item was added:
+ ----- Method: MailMessage>>readStringLineFrom: (in category 'parsing') -----
+ readStringLineFrom: aStream 
+ 	"Read and answer the next line from the given stream. Consume the carriage return but do not append it to the string."
+ 
+ 	^aStream nextLine!

Item was changed:
  Object subclass: #NetNameResolver
  	instanceVariableNames: ''
+ 	classVariableNames: 'DefaultHostName HaveNetwork ResolverBusy ResolverError ResolverMutex ResolverReady ResolverSemaphore ResolverUninitialized UseOldNetwork'
- 	classVariableNames: 'DefaultHostName HaveNetwork ResolverBusy ResolverError ResolverMutex ResolverReady ResolverSemaphore ResolverUninitialized'
  	poolDictionaries: ''
  	category: 'Network-Kernel'!
  
  !NetNameResolver commentStamp: '<historical>' prior: 0!
  This class implements TCP/IP style network name lookup and translation facilities.
  
  Attempt to keep track of whether there is a network available.
  HaveNetwork	true if last attempt to contact the network was successful.
  LastContact		Time of that contact (totalSeconds).
  haveNetwork	returns true, false, or #expired.  True means there was contact in the last 30 minutes.  False means contact failed or was false last time we asked.  Get out of false state by making contact with a server in some way (FileList or updates).!

Item was changed:
  ----- Method: NetNameResolver class>>addressForName: (in category 'lookups') -----
+ addressForName: hostName
+ 	"NetNameResolver addressForName: 'impara.de' "
+ 	"NetNameResolver addressForName: 'localhost' "
+ 	"NetNameResolver addressForName: '127.0.0.1' "
+ 	| addresses |
+ 	self useOldNetwork
+ 		ifTrue: [^self oldAddressForName: hostName].
+ 	addresses := self addressesForName: hostName.
+ 	^addresses
+ 		ifEmpty: [nil]
+ 		ifNotEmpty: [addresses first socketAddress]!
- addressForName: aString
- 	^self addressForName: aString timeout: 60!

Item was changed:
  ----- Method: NetNameResolver class>>addressForName:timeout: (in category 'lookups') -----
  addressForName: hostName timeout: secs
  	"Look up the given host name and return its address. Return nil if the address is not found in the given number of seconds."
  	"NetNameResolver addressForName: 'create.ucsb.edu' timeout: 30"
  	"NetNameResolver addressForName: '100000jobs.de' timeout: 30"
  	"NetNameResolver addressForName: '1.7.6.4' timeout: 30"
  	"NetNameResolver addressForName: '' timeout: 30 (This seems to return nil?)"
  
  	| deadline result |
  	self initializeNetwork.
+ 	self useOldNetwork
+ 		ifFalse: [^self addressForName: hostName].
  	"check if this is a valid numeric host address (e.g. 1.2.3.4)"
  	result := self addressFromString: hostName.
+ 	result isNil ifFalse: [^result asSocketAddress].
- 	result ifNotNil: [^result].
  
  	"Look up a host name, including ones that start with a digit (e.g. 100000jobs.de or squeak.org)"
  	deadline := Time millisecondClockValue + (secs * 1000).
  	"Protect the execution of this block, as the ResolverSemaphore is used for both parts of the transaction."
  	self resolverMutex
  		critical: [
  			(self waitForResolverReadyUntil: deadline)
  				ifTrue: [
  					self primStartLookupOfName: hostName.
  					(self waitForCompletionUntil: deadline)
  						ifTrue: [result := self primNameLookupResult]
  						ifFalse: [(NameLookupFailure hostName: hostName) signal: 'Could not resolve the server named: ', hostName]]
  				ifFalse: [(NameLookupFailure hostName: hostName) signal: 'Could not resolve the server named: ', hostName]].
+ 	^result asSocketAddress!
- 	^result!

Item was added:
+ ----- Method: NetNameResolver class>>addressesForName: (in category 'lookup') -----
+ addressesForName: hostName
+ 	"NetNameResolver addressesForName: 'impara.de' "
+ 	
+ 	| addresses |
+ 	addresses := SocketAddressInformation
+ 		forHost: hostName
+ 		service: ''
+ 		flags: 0
+ 		addressFamily: 0
+ 		socketType: SocketAddressInformation socketTypeStream
+ 		protocol: SocketAddressInformation protocolTCP.
+ 	^addresses!

Item was changed:
  ----- Method: NetNameResolver class>>initializeNetwork (in category 'network initialization') -----
  initializeNetwork
  	"Initialize the network drivers and record the semaphore to be used by the resolver. Do nothing if the network is already initialized. Evaluate the given block if network initialization fails."
+ 	"NetNameResolver initializeNetwork" 
- 	"NetNameResolver initializeNetwork"
  
  	| semaIndex |
  	self resolverStatus = ResolverUninitialized
  		ifFalse: [^HaveNetwork := true].  "network is already initialized"
  
  	HaveNetwork := false.	"in case abort"
  	ResolverSemaphore := Semaphore new.
  	semaIndex := Smalltalk registerExternalObject: ResolverSemaphore.
  
  	"result is nil if network initialization failed, self if it succeeds"
  	(self primInitializeNetwork: semaIndex)
  		ifNil: [NoNetworkError signal: 'failed network initialization']
  		ifNotNil: [HaveNetwork := true].
+ 
+ 	UseOldNetwork := [NetNameResolver primHostNameSize. false]
+ 		on: Error
+ 		do: [:ex | ex return: true]
  !

Item was changed:
  ----- Method: NetNameResolver class>>localAddressString (in category 'lookups') -----
  localAddressString
  	"Return a string representing the local host address as four decimal bytes delimited with decimal points."
  	"NetNameResolver localAddressString"
  
+ 	self useOldNetwork
+ 		ifTrue: [^self stringFromAddress: self primLocalAddress].
+ 	^self localHostAddress hostNumber!
- 	^ NetNameResolver stringFromAddress: NetNameResolver localHostAddress
- !

Item was changed:
  ----- Method: NetNameResolver class>>localHostAddress (in category 'lookups') -----
  localHostAddress
  	"Return the local address of this host."
  	"NetNameResolver localHostAddress"
  
+ 	self useOldNetwork ifTrue: [
+ 		self initializeNetwork.
+ 		^self primLocalAddress ].
+ 	^NetNameResolver addressForName: self localHostName!
- 	self initializeNetwork.
- 	^ self primLocalAddress
- !

Item was changed:
  ----- Method: NetNameResolver class>>localHostName (in category 'lookups') -----
  localHostName
  	"Return the local name of this host."
  	"NetNameResolver localHostName"
  
+ 	| host |
+ 	self useOldNetwork ifTrue: [
+ 		| hostName |
+ 		hostName := self
+ 			nameForAddress: self localHostAddress
+ 			timeout: 5.
+ 		^hostName ifNil: [ self localAddressString ] ].
+ 	host := String new: NetNameResolver primHostNameSize.
+ 	NetNameResolver primHostNameResult: host.
+ 	^host!
- 	| hostName |
- 	hostName := NetNameResolver
- 		nameForAddress: self localHostAddress
- 		timeout: 5.
- 	^hostName
- 		ifNil: [self localAddressString]
- 		ifNotNil: [hostName]!

Item was added:
+ ----- Method: NetNameResolver class>>nextSocketAddressInformation (in category 'private') -----
+ nextSocketAddressInformation
+ 
+ 	| addrSize addr info |
+ 	addrSize := self primGetAddressInfoSize.
+ 	addrSize < 0 ifTrue: [^nil].
+ 	addr := SocketAddress new: addrSize.
+ 	self primGetAddressInfoResult: addr.
+ 	info := SocketAddressInformation
+ 		withSocketAddress: addr
+ 		family: self primGetAddressInfoFamily
+ 		type: self primGetAddressInfoType
+ 		protocol: self primGetAddressInfoProtocol.
+ 	self primGetAddressInfoNext.
+ 	^info!

Item was added:
+ ----- Method: NetNameResolver class>>oldAddressForName: (in category 'lookups-old') -----
+ oldAddressForName: aString
+ 	"NetNameResolver oldAddressForName: 'vpri.org' "
+ 	^self addressForName: aString timeout: 60!

Item was added:
+ ----- Method: NetNameResolver class>>primGetAddressInfoFamily (in category 'primitives-ipv6') -----
+ primGetAddressInfoFamily
+ 
+ 	<primitive: 'primitiveResolverGetAddressInfoFamily' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetAddressInfoHost:service:flags:family:type:protocol: (in category 'primitives-ipv6') -----
+ primGetAddressInfoHost: hostName service: servName flags: flags family: family type: type protocol: protocol
+ 
+ 	<primitive: 'primitiveResolverGetAddressInfo' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetAddressInfoNext (in category 'primitives-ipv6') -----
+ primGetAddressInfoNext
+ 
+ 	<primitive: 'primitiveResolverGetAddressInfoNext' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetAddressInfoProtocol (in category 'primitives-ipv6') -----
+ primGetAddressInfoProtocol
+ 
+ 	<primitive: 'primitiveResolverGetAddressInfoProtocol' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetAddressInfoResult: (in category 'primitives-ipv6') -----
+ primGetAddressInfoResult: socketAddress
+ 
+ 	<primitive: 'primitiveResolverGetAddressInfoResult' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetAddressInfoSize (in category 'primitives-ipv6') -----
+ primGetAddressInfoSize
+ 
+ 	<primitive: 'primitiveResolverGetAddressInfoSize' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetAddressInfoType (in category 'primitives-ipv6') -----
+ primGetAddressInfoType
+ 
+ 	<primitive: 'primitiveResolverGetAddressInfoType' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetNameInfo:flags: (in category 'primitives-ipv6') -----
+ primGetNameInfo: socketAddress flags: flags
+ 
+ 	<primitive: 'primitiveResolverGetNameInfo' module: 'SocketPlugin'>
+ 	flags == 0 ifTrue: [^self primGetNameInfo: socketAddress
+ 						flags: SocketAddressInformation numericFlag].
+ 	self primitiveFailed!

Item was added:
+ ----- Method: NetNameResolver class>>primGetNameInfoHostResult: (in category 'primitives-ipv6') -----
+ primGetNameInfoHostResult: aString
+ 
+ 	<primitive: 'primitiveResolverGetNameInfoHostResult' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetNameInfoHostSize (in category 'primitives-ipv6') -----
+ primGetNameInfoHostSize
+ 
+ 	<primitive: 'primitiveResolverGetNameInfoHostSize' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetNameInfoServiceResult: (in category 'primitives-ipv6') -----
+ primGetNameInfoServiceResult: aString
+ 
+ 	<primitive: 'primitiveResolverGetNameInfoServiceResult' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primGetNameInfoServiceSize (in category 'primitives-ipv6') -----
+ primGetNameInfoServiceSize
+ 
+ 	<primitive: 'primitiveResolverGetNameInfoServiceSize' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primHostNameResult: (in category 'primitives-ipv6') -----
+ primHostNameResult: aString
+ 
+ 	<primitive: 'primitiveResolverHostNameResult' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>primHostNameSize (in category 'primitives-ipv6') -----
+ primHostNameSize
+ 
+ 	<primitive: 'primitiveResolverHostNameSize' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: NetNameResolver class>>testIPv6 (in category 'tests') -----
+ testIPv6
+ 	"NetNameResolver testIPv6"
+ 	| infos addr sock size host serverSocket listeningSocket clientSocket |
+ 	World findATranscript: World currentEvent.
+ 	Transcript clear.
+ 	"Transcript show: SmalltalkImage current listLoadedModules; cr."
+ 	self initializeNetwork.
+ 	Transcript show: '---- host name ----'; cr.
+ 	size := NetNameResolver primHostNameSize.
+ 	host := String new: size.
+ 	NetNameResolver primHostNameResult: host.
+ 	Transcript show: host; cr.
+ 	Transcript show: '---- address information ----'; cr.
+ 	Transcript show: (infos := SocketAddressInformation
+ 						forHost: 'localhost' service: 'echo' flags: 0
+ 						addressFamily: 0 socketType: 0 protocol: 0) printString; cr.
+ 	Transcript show: '---- port manipulation ----'; cr.
+ 	addr := infos first socketAddress.
+ 	Transcript show: addr port printString; cr.
+ 	addr port: 1234.
+ 	Transcript show: addr port printString; cr.
+ 	Transcript show: addr printString; cr.
+ 	Transcript show: '---- client socket ----'; cr.
+ 	Transcript show: (infos := SocketAddressInformation
+ 						forHost: 'localhost' service: 'echo' flags: 0
+ 						addressFamily: 0
+ 						socketType: SocketAddressInformation socketTypeStream
+ 						protocol: SocketAddressInformation protocolTCP) printString; cr.
+ 	infos do: [:info |
+ 		Transcript show: 'Trying ', info printString, '... '.
+ 		(sock := info connect) notNil
+ 			ifTrue:
+ 				[sock sendData: 'hello' count: 5.
+ 				 Transcript show: sock receiveData printString.
+ 				 sock close; destroy].
+ 		Transcript cr].
+ 	Transcript show: '---- localhost defaults: loopback and wildcard addresses ----'; cr.
+ 	Transcript show: (SocketAddress loopbacks) printString; cr.
+ 	Transcript show: (SocketAddress wildcards) printString; cr.
+ 	Transcript show: (SocketAddress loopback4) printString; cr.
+ 	Transcript show: (SocketAddress wildcard4) printString; cr.
+ 	Transcript show: '---- impossible constraints ----'; cr.
+ 	Transcript show: (SocketAddressInformation
+ 						forHost: 'localhost' service: 'echo' flags: 0
+ 						addressFamily:	0
+ 						socketType:		SocketAddressInformation socketTypeDGram
+ 						protocol:		SocketAddressInformation protocolTCP) printString; cr.
+ 	Transcript show: '---- INET4 client-server ----'; cr.
+ 	Transcript show: (infos := SocketAddressInformation
+ 						forHost: '' service: '4242'
+ 						flags:			SocketAddressInformation passiveFlag
+ 						addressFamily:	SocketAddressInformation addressFamilyINET4
+ 						socketType:		SocketAddressInformation socketTypeStream
+ 						protocol:		SocketAddressInformation protocolTCP) printString; cr.
+ 	listeningSocket := infos first listenWithBacklog: 5.
+ 	Transcript show: (infos := SocketAddressInformation
+ 						forHost: 'localhost' service: '4242'
+ 						flags:			0
+ 						addressFamily:	SocketAddressInformation addressFamilyINET4
+ 						socketType:		SocketAddressInformation socketTypeStream
+ 						protocol:		SocketAddressInformation protocolTCP) printString; cr.
+ 	clientSocket := infos first connect.
+ 	serverSocket := listeningSocket accept.
+ 	serverSocket sendData: 'Hi there!!' count: 9.
+ 	Transcript show: clientSocket receiveData; cr.
+ 	Transcript nextPutAll: 'client side local/remote: ';
+ 		print: clientSocket localSocketAddress; space;
+ 		print: clientSocket remoteSocketAddress; cr.
+ 	Transcript nextPutAll: 'server side local/remote: ';
+ 		print: serverSocket localSocketAddress; space;
+ 		print: serverSocket remoteSocketAddress; cr;
+ 		endEntry.
+ 	clientSocket close; destroy.
+ 	serverSocket close; destroy.
+ 	listeningSocket close; destroy.
+ 	Transcript show: '---- INET6 client-server ----'; cr.
+ 	Transcript show: (infos := SocketAddressInformation
+ 						forHost: '' service: '4242'
+ 						flags:			SocketAddressInformation passiveFlag
+ 						addressFamily:	SocketAddressInformation addressFamilyINET6
+ 						socketType:		SocketAddressInformation socketTypeStream
+ 						protocol:		SocketAddressInformation protocolTCP) printString; cr.
+ 	infos isEmpty
+ 		ifTrue: [Transcript show: 'FAIL -- CANNOT CREATE INET6 SERVER'; cr]
+ 		ifFalse:
+ 			[listeningSocket := infos first listenWithBacklog: 5.
+ 			Transcript show: (infos := SocketAddressInformation
+ 								forHost: 'localhost' service: '4242'
+ 								flags:			0
+ 								addressFamily:	SocketAddressInformation addressFamilyINET6
+ 								socketType:		SocketAddressInformation socketTypeStream
+ 								protocol:		SocketAddressInformation protocolTCP) printString; cr.
+ 			clientSocket := infos first connect.
+ 			serverSocket := listeningSocket accept.
+ 			serverSocket sendData: 'Hi there!!' count: 9.
+ 			Transcript show: clientSocket receiveData; cr.
+ 			Transcript nextPutAll: 'client side local/remote: ';
+ 				print: clientSocket localSocketAddress; space;
+ 				print: clientSocket remoteSocketAddress; cr.
+ 			Transcript nextPutAll: 'server side local/remote: ';
+ 				print: serverSocket localSocketAddress; space;
+ 				print: serverSocket remoteSocketAddress; cr;
+ 				endEntry.
+ 			clientSocket close; destroy.
+ 			serverSocket close; destroy.
+ 			listeningSocket close; destroy].
+ 	Transcript show: '---- trivial tests done ---'; cr.!

Item was added:
+ ----- Method: NetNameResolver class>>testPort80 (in category 'tests') -----
+ testPort80
+ 	"NetNameResolver testPort80"
+ 	| infos |
+ 	Transcript show: (infos := SocketAddressInformation
+ 						forHost: 'localhost' service: '80' flags: 0
+ 						addressFamily: 0 socketType: 0 protocol: 0) printString; cr.
+ 	Transcript show: (infos := SocketAddressInformation
+ 						forHost: '::1' service: '80' flags: 0
+ 						addressFamily: 0 socketType: 0 protocol: 0) printString; cr.
+ !

Item was added:
+ ----- Method: NetNameResolver class>>useOldNetwork (in category 'private') -----
+ useOldNetwork
+ 	^UseOldNetwork ~~ false!

Item was added:
+ ----- Method: NetNameResolver class>>useOldNetwork: (in category 'private') -----
+ useOldNetwork: flag
+ 	"Unit test support, not intended for public access"
+ 	^UseOldNetwork := flag!

Item was changed:
  ----- Method: ProtocolClient>>ensureConnection (in category 'private') -----
  ensureConnection
  	self isConnected
  		ifTrue: [^self].
  	self stream
  		ifNotNil: [self stream close].
  
+ 	self stream: (SocketStream openConnectionToHost: self host port: self port).
- 	self stream: (SocketStream openConnectionToHost: self host port: self port timeout: self standardTimeout).
  	self checkResponse.
  	self login!

Item was added:
+ ----- Method: SMTPClient class>>openOnHost:port: (in category 'instance creation') -----
+ openOnHost: hostIP port: portNumber
+ 
+ 	| client |
+ 	client := super openOnHost: hostIP port: portNumber.
+ 	client initiateSession.
+ 	^client!

Item was changed:
  Object subclass: #Socket
+ 	instanceVariableNames: 'semaphore socketHandle readSemaphore writeSemaphore primitiveOnlySupportsOneSemaphore'
- 	instanceVariableNames: 'semaphore socketHandle readSemaphore writeSemaphore'
  	classVariableNames: 'Connected DeadServer InvalidSocket OtherEndClosed Registry RegistryThreshold TCPSocketType ThisEndClosed UDPSocketType Unconnected WaitingForConnection'
  	poolDictionaries: ''
  	category: 'Network-Kernel'!
  
  !Socket commentStamp: 'gk 12/13/2005 00:43' prior: 0!
  A Socket represents a network connection point. Current sockets are designed to support the TCP/IP and UDP protocols. Sockets are the lowest level of networking object in Squeak and are not normally used directly. SocketStream is a higher level object wrapping a Socket in a stream like protocol.
  
  ProtocolClient and subclasses are in turn wrappers around a SocketStream to provide support for specific network protocols such as POP, NNTP, HTTP, and FTP.!

Item was changed:
  ----- Method: Socket class>>newTCP (in category 'instance creation') -----
  newTCP
  	"Create a socket and initialise it for TCP"
+ 	^self newTCP: SocketAddressInformation addressFamilyINET4!
- 	self initializeNetwork.
- 	^[ super new initialize: TCPSocketType ]
- 		repeatWithGCIf: [ :socket | socket isValid not ]!

Item was added:
+ ----- Method: Socket class>>newTCP: (in category 'instance creation') -----
+ newTCP: family
+ 	"Create a socket and initialise it for TCP"
+ 	self initializeNetwork.
+ 	^[ super new initialize: TCPSocketType family: family ]
+ 		repeatWithGCIf: [ :socket | socket isValid not ]!

Item was changed:
  ----- Method: Socket class>>newUDP (in category 'instance creation') -----
  newUDP
  	"Create a socket and initialise it for UDP"
+ 	^self newUDP: SocketAddressInformation addressFamilyINET4!
- 	self initializeNetwork.
- 	^[ super new initialize: UDPSocketType ]
- 		repeatWithGCIf: [ :socket | socket isValid not ]!

Item was added:
+ ----- Method: Socket class>>newUDP: (in category 'instance creation') -----
+ newUDP: family
+ 	"Create a socket and initialise it for UDP"
+ 	self initializeNetwork.
+ 	^[ super new initialize: UDPSocketType family: family ]
+ 		repeatWithGCIf: [ :socket | socket isValid not ]!

Item was changed:
  ----- Method: Socket class>>tcpCreateIfFail: (in category 'instance creation') -----
  tcpCreateIfFail: failBlock
  	"Attempt to create a new socket. If successful, return the new socket. Otherwise, return the result of evaluating the given block. Socket creation can fail if the network isn't available or if there are not sufficient resources available to create another socket."
  
  	| sock |
  	self initializeNetwork.
+ 	sock := self newTCP.
- 	sock := super new initialize: TCPSocketType.
  	sock isValid ifFalse: [^ failBlock value].
  	^ sock
  !

Item was added:
+ ----- Method: Socket class>>timeTest (in category 'examples') -----
+ timeTest
+ 	"Socket timeTest"
+ 
+ 	| serverName serverAddr s |
+ 	Transcript show: 'initializing network ... '.
+ 	self initializeNetwork.
+ 	Transcript
+ 		show: 'ok';
+ 		cr.
+ 	serverName := UIManager default request: 'What is your time server?'
+ 				initialAnswer: 'localhost'.
+ 	serverName isEmpty 
+ 		ifTrue: 
+ 			[^Transcript
+ 				show: 'never mind';
+ 				cr].
+ 	serverAddr := NetNameResolver addressForName: serverName timeout: 10.
+ 	serverAddr = nil 
+ 		ifTrue: [self error: 'Could not find the address for ' , serverName].
+ 	s := self new.
+ 	Transcript
+ 		show: '---------- Connecting ----------';
+ 		cr.
+ 	s connectTo: serverAddr port: 13.	"13 is the 'daytime' port number"
+ 	s waitForConnectionUntil: (self deadlineSecs: 1).
+ 	Transcript show: 'the time server reports: ' , s receiveData.
+ 	s closeAndDestroy.
+ 	Transcript
+ 		show: '---------- Connection Closed ----------';
+ 		cr!

Item was added:
+ ----- Method: Socket class>>timeTestUDP (in category 'examples') -----
+ timeTestUDP
+ 	"Socket timeTestUDP"
+ 
+ 	| serverName serverAddr s |
+ 	Transcript show: 'initializing network ... '.
+ 	self initializeNetwork.
+ 	Transcript
+ 		show: 'ok';
+ 		cr.
+ 	serverName := UIManager default request: 'What is your time server?'
+ 				initialAnswer: 'localhost'.
+ 	serverName isEmpty 
+ 		ifTrue: 
+ 			[^Transcript
+ 				show: 'never mind';
+ 				cr].
+ 	serverAddr := NetNameResolver addressForName: serverName timeout: 10.
+ 	serverAddr = nil 
+ 		ifTrue: [self error: 'Could not find the address for ' , serverName].
+ 	s := self newUDP.	"a 'random' port number will be allocated by the system"
+ 	"Send a packet to the daytime port and it will reply with the current date."
+ 	Transcript
+ 		show: '---------- Sending datagram from port ' , s port printString 
+ 					, ' ----------';
+ 		cr.
+ 	s 
+ 		sendData: '!!'
+ 		toHost: serverAddr
+ 		port: 13.	"13 is the daytime service"
+ 	Transcript show: 'the time server reports: ' , s receiveData.
+ 	s closeAndDestroy.
+ 	Transcript
+ 		show: '---------- Socket closed ----------';
+ 		cr!

Item was changed:
  ----- Method: Socket class>>udpCreateIfFail: (in category 'instance creation') -----
  udpCreateIfFail: failBlock
  	"Attempt to create a new socket. If successful, return the new socket. Otherwise, return the result of evaluating the given block. Socket creation can fail if the network isn't available or if there are not sufficient resources available to create another socket."
  
  	| sock |
  	self initializeNetwork.
+ 	sock := self newUDP.
- 	sock := super new initialize: UDPSocketType.
  	sock isValid ifFalse: [^ failBlock value].
  	^ sock
  !

Item was changed:
  ----- Method: Socket>>acceptFrom: (in category 'initialize-destroy') -----
  acceptFrom: aSocket
  	"Initialize a new socket handle from an accept call"
  	| semaIndex readSemaIndex writeSemaIndex |
  
+ 	primitiveOnlySupportsOneSemaphore := false.
  	semaphore := Semaphore new.
  	readSemaphore := Semaphore new.
  	writeSemaphore := Semaphore new.
  	semaIndex := Smalltalk registerExternalObject: semaphore.
  	readSemaIndex := Smalltalk registerExternalObject: readSemaphore.
  	writeSemaIndex := Smalltalk registerExternalObject: writeSemaphore.
  	socketHandle := self primAcceptFrom: aSocket socketHandle
  						receiveBufferSize: 8000
  						sendBufSize: 8000
  						semaIndex: semaIndex
  						readSemaIndex: readSemaIndex
  						writeSemaIndex: writeSemaIndex.
  	socketHandle
  		ifNotNil: [ self register ]
  		ifNil: [  "socket creation failed"
  			Smalltalk unregisterExternalObject: semaphore.
  			Smalltalk unregisterExternalObject: readSemaphore.
  			Smalltalk unregisterExternalObject: writeSemaphore.
  			readSemaphore := writeSemaphore := semaphore := nil ]
  !

Item was added:
+ ----- Method: Socket>>bindTo: (in category 'ipv6') -----
+ bindTo: aSocketAddress
+ 
+ 	| status |
+ 	self initializeNetwork.
+ 	status := self primSocketConnectionStatus: socketHandle.
+ 	(status == Unconnected)
+ 		ifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected when binding it to an address'].
+ 
+ 	self primSocket: socketHandle bindTo: aSocketAddress.
+ !

Item was added:
+ ----- Method: Socket>>connectNonBlockingTo: (in category 'ipv6') -----
+ connectNonBlockingTo: aSocketAddress
+ 
+ 	| status |
+ 	self initializeNetwork.
+ 	status := self primSocketConnectionStatus: socketHandle.
+ 	(status == Unconnected)
+ 		ifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected before opening a new connection'].
+ 
+ 	self primSocket: socketHandle connectTo: aSocketAddress.
+ !

Item was changed:
  ----- Method: Socket>>connectNonBlockingTo:port: (in category 'connection open/close') -----
  connectNonBlockingTo: hostAddress port: port
  	"Initiate a connection to the given port at the given host address. This operation will return immediately; follow it with waitForConnectionUntil: to wait until the connection is established."
  
  	| status |
  	self initializeNetwork.
  	status := self primSocketConnectionStatus: socketHandle.
  	(status == Unconnected)
  		ifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected before opening a new connection'].
  
+ 	NetNameResolver useOldNetwork
+ 		ifTrue: [self primSocket: socketHandle connectTo: hostAddress port: port]
+ 		ifFalse: [ | socketAddress |
+ 			socketAddress := hostAddress asSocketAddress.
+ 			socketAddress port: port.
+ 			self connectNonBlockingTo: socketAddress]!
- 	self primSocket: socketHandle connectTo: hostAddress port: port.
- !

Item was added:
+ ----- Method: Socket>>connectTo: (in category 'ipv6') -----
+ connectTo: aSocketAddress
+ 
+ 	self connectTo: aSocketAddress waitForConnectionFor: Socket standardTimeout!

Item was changed:
  ----- Method: Socket>>connectTo:port: (in category 'connection open/close') -----
  connectTo: hostAddress port: port
  	"Initiate a connection to the given port at the given host address.
  	Waits until the connection is established or time outs."
  
+ 	NetNameResolver useOldNetwork
+ 		ifTrue: [self connectTo: hostAddress port: port waitForConnectionFor: Socket standardTimeout]
+ 		ifFalse: [ | socketAddress |
+ 			socketAddress := hostAddress asSocketAddress.
+ 			socketAddress port: port.
+ 			self connectTo: socketAddress]!
- 	self connectTo: hostAddress port: port waitForConnectionFor: Socket standardTimeout!

Item was changed:
  ----- Method: Socket>>connectTo:port:waitForConnectionFor: (in category 'connection open/close') -----
  connectTo: hostAddress port: port waitForConnectionFor: timeout 
  	"Initiate a connection to the given port at the given host 
  	address. Waits until the connection is established or time outs."
  	self connectNonBlockingTo: hostAddress port: port.
  	self
  		waitForConnectionFor: timeout
  		ifTimedOut: [ConnectionTimedOut signal: 'Cannot connect to '
+ 					, self remoteSocketAddress hostNumber , ':' , port asString]!
- 					, (NetNameResolver stringFromAddress: hostAddress) , ':' , port asString]!

Item was added:
+ ----- Method: Socket>>connectTo:waitForConnectionFor: (in category 'ipv6') -----
+ connectTo: aSocketAddress waitForConnectionFor: timeout 
+ 
+ 	self connectNonBlockingTo: aSocketAddress.
+ 	self
+ 		waitForConnectionFor: timeout
+ 		ifTimedOut: [ConnectionTimedOut signal: 'Cannot connect to ', aSocketAddress printString]!

Item was changed:
  ----- Method: Socket>>discardReceivedData (in category 'receiving') -----
  discardReceivedData
  	"Discard any data received up until now, and return the number of bytes discarded."
  
  	| buf totalBytesDiscarded |
  	buf := String new: 10000.
  	totalBytesDiscarded := 0.
+ 	[self isConnected and: [self dataAvailable]] whileTrue: [
- 	[self isConnected] whileTrue: [
  		totalBytesDiscarded :=
  			totalBytesDiscarded + (self receiveDataInto: buf)].
  	^ totalBytesDiscarded
  !

Item was changed:
  ----- Method: Socket>>initialize: (in category 'initialize-destroy') -----
  initialize: socketType
  	"Initialize a new socket handle. If socket creation fails, socketHandle will be set to nil."
  	| semaIndex readSemaIndex writeSemaIndex |
  
+ 	primitiveOnlySupportsOneSemaphore := false.
  	semaphore := Semaphore new.
  	readSemaphore := Semaphore new.
  	writeSemaphore := Semaphore new.
  	semaIndex := Smalltalk registerExternalObject: semaphore.
  	readSemaIndex := Smalltalk registerExternalObject: readSemaphore.
  	writeSemaIndex := Smalltalk registerExternalObject: writeSemaphore.
  	socketHandle :=
  		self primSocketCreateNetwork: 0
  			type: socketType
  			receiveBufferSize: 8000
  			sendBufSize: 8000
  			semaIndex: semaIndex
  			readSemaIndex: readSemaIndex
  			writeSemaIndex: writeSemaIndex.
  
  	socketHandle 
  		ifNotNil: [ self register ]
  		ifNil: [  "socket creation failed"
  			Smalltalk unregisterExternalObject: semaphore.
  			Smalltalk unregisterExternalObject: readSemaphore.
  			Smalltalk unregisterExternalObject: writeSemaphore.
  			readSemaphore := writeSemaphore := semaphore := nil ]
  !

Item was added:
+ ----- Method: Socket>>initialize:family: (in category 'initialize-destroy') -----
+ initialize: socketType family: family
+ 	"Initialize a new socket handle. If socket creation fails, socketHandle will be set to nil."
+ 	| semaIndex readSemaIndex writeSemaIndex |
+ 
+ 	NetNameResolver useOldNetwork ifTrue: [^self initialize: socketType].
+ 	primitiveOnlySupportsOneSemaphore := false.
+ 	semaphore := Semaphore new.
+ 	readSemaphore := Semaphore new.
+ 	writeSemaphore := Semaphore new.
+ 	semaIndex := Smalltalk registerExternalObject: semaphore.
+ 	readSemaIndex := Smalltalk registerExternalObject: readSemaphore.
+ 	writeSemaIndex := Smalltalk registerExternalObject: writeSemaphore.
+ 	socketHandle :=
+ 		self primSocketCreateNetwork: family
+ 			type: socketType
+ 			receiveBufferSize: 8000
+ 			sendBufSize: 8000
+ 			semaIndex: semaIndex
+ 			readSemaIndex: readSemaIndex
+ 			writeSemaIndex: writeSemaIndex.
+ 
+ 	socketHandle
+ 		ifNotNil: [ self register ]
+ 		ifNil: [  "socket creation failed"
+ 			Smalltalk unregisterExternalObject: semaphore.
+ 			Smalltalk unregisterExternalObject: readSemaphore.
+ 			Smalltalk unregisterExternalObject: writeSemaphore.
+ 			readSemaphore := writeSemaphore := semaphore := nil ]
+ !

Item was changed:
  ----- Method: Socket>>listenOn:backlogSize:interface: (in category 'connection open/close') -----
  listenOn: portNumber backlogSize: backlog interface: ifAddr
  	"Listen for a connection on the given port.
  	If this method succeeds, #accept may be used to establish a new connection"
  	| status |
  	status := self primSocketConnectionStatus: socketHandle.
  	(status == Unconnected)
  		ifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected before listening for a new connection'].
+ 	self primSocket: socketHandle listenOn: portNumber backlogSize: backlog interface: ifAddr asByteArray.
- 	self primSocket: socketHandle listenOn: portNumber backlogSize: backlog interface: ifAddr.
  !

Item was added:
+ ----- Method: Socket>>listenWithBacklog: (in category 'ipv6') -----
+ listenWithBacklog: backlogSize
+ 
+ 	| status |
+ 	self initializeNetwork.
+ 	status := self primSocketConnectionStatus: socketHandle.
+ 	(status == Unconnected)
+ 		ifFalse: [InvalidSocketStatusException signal: 'Socket status must Unconnected before it can listen for connections'].
+ 
+ 	self primSocket: socketHandle listenWithBacklog: backlogSize.
+ !

Item was changed:
  ----- Method: Socket>>localAddress (in category 'accessing') -----
  localAddress
  
  	self isWaitingForConnection ifFalse: [
  		self
  			waitForConnectionFor: Socket standardTimeout
+ 			ifTimedOut: [
+ 				NetNameResolver useOldNetwork
+ 					ifTrue: [^ByteArray new: 4]
+ 					ifFalse: [^(ByteArray new: 4) asSocketAddress]]].
+ 	NetNameResolver useOldNetwork
+ 		ifTrue: [^self primSocketLocalAddress: socketHandle]
+ 		ifFalse: [^(self primSocketLocalAddress: socketHandle) asSocketAddress]
+ !
- 			ifTimedOut: [ ^ByteArray new: 4 ] ].
- 	^self primSocketLocalAddress: socketHandle!

Item was added:
+ ----- Method: Socket>>localSocketAddress (in category 'ipv6') -----
+ localSocketAddress
+ 
+ 	| size addr |
+ 	size := self primSocketLocalAddressSize: socketHandle.
+ 	addr := SocketAddress new: size.
+ 	self primSocket: socketHandle localAddressResult: addr.
+ 	^addr!

Item was changed:
  ----- Method: Socket>>peerName (in category 'accessing') -----
  peerName
  	"Return the name of the host I'm connected to, or nil if its name isn't known to the domain name server or the request times out."
  	"Note: Slow. Calls the domain name server, taking up to 20 seconds to time out. Even when sucessful, delays of up to 13 seconds have been observed during periods of high network load." 
  
+ 	^self remoteSocketAddress hostName!
- 	^ NetNameResolver
- 		nameForAddress: self remoteAddress
- 		timeout: 20
- !

Item was changed:
  ----- Method: Socket>>primAcceptFrom:receiveBufferSize:sendBufSize:semaIndex:readSemaIndex:writeSemaIndex: (in category 'primitives') -----
  primAcceptFrom: aHandle receiveBufferSize: rcvBufSize sendBufSize: sndBufSize semaIndex: semaIndex readSemaIndex: aReadSema writeSemaIndex: aWriteSema
  	"Create and return a new socket handle based on accepting the connection from the given listening socket"
- 	
  	<primitive: 'primitiveSocketAccept3Semaphores' module: 'SocketPlugin'>
+ 	primitiveOnlySupportsOneSemaphore := true.
+ 	^self primAcceptFrom: aHandle receiveBufferSize: rcvBufSize sendBufSize: sndBufSize semaIndex: semaIndex !
- 	self primitiveFailed!

Item was added:
+ ----- Method: Socket>>primSocket:bindTo: (in category 'primitives-ipv6') -----
+ primSocket: socketID bindTo: socketAddress
+ 
+ 	<primitive: 'primitiveSocketBindTo' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: Socket>>primSocket:connectTo: (in category 'primitives-ipv6') -----
+ primSocket: socketID connectTo: socketAddress
+ 
+ 	<primitive: 'primitiveSocketConnectTo' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was changed:
  ----- Method: Socket>>primSocket:getOption: (in category 'primitives') -----
  primSocket: socketID getOption: aString 
  	"Get some option information on this socket. Refer to the UNIX 
  	man pages for valid SO, TCP, IP, UDP options. In case of doubt
  	refer to the source code.
+ 	TCP_NODELAY, SO_KEEPALIVE are valid options for example
- 	TCP:=NODELAY, SO:=KEEPALIVE are valid options for example
  	returns an array containing the error code and the option value"
  
  	<primitive: 'primitiveSocketGetOptions' module: 'SocketPlugin'>
  	self primitiveFailed
  !

Item was added:
+ ----- Method: Socket>>primSocket:listenWithBacklog: (in category 'primitives-ipv6') -----
+ primSocket: socketID listenWithBacklog: backlogSize
+ 
+ 	<primitive: 'primitiveSocketListenWithBacklog' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: Socket>>primSocket:localAddressResult: (in category 'primitives-ipv6') -----
+ primSocket: socketID localAddressResult: socketAddress
+ 
+ 	<primitive: 'primitiveSocketLocalAddressResult' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: Socket>>primSocket:remoteAddressResult: (in category 'primitives-ipv6') -----
+ primSocket: socketID remoteAddressResult: socketAddress
+ 
+ 	<primitive: 'primitiveSocketRemoteAddressResult' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was changed:
  ----- Method: Socket>>primSocket:setOption:value: (in category 'primitives') -----
  primSocket: socketID setOption: aString value: aStringValue
  	"Set some option information on this socket. Refer to the UNIX 
  	man pages for valid SO, TCP, IP, UDP options. In case of doubt
  	refer to the source code.
+ 	TCP_NODELAY, SO_KEEPALIVE are valid options for example
- 	TCP:=NODELAY, SO:=KEEPALIVE are valid options for example
  	returns an array containing the error code and the negotiated value"
  
  	<primitive: 'primitiveSocketSetOptions' module: 'SocketPlugin'>
  	^nil!

Item was changed:
  ----- Method: Socket>>primSocketCreateNetwork:type:receiveBufferSize:sendBufSize:semaIndex:readSemaIndex:writeSemaIndex: (in category 'primitives') -----
  primSocketCreateNetwork: netType type: socketType receiveBufferSize: rcvBufSize sendBufSize: sendBufSize semaIndex: semaIndex readSemaIndex: aReadSema writeSemaIndex: aWriteSema
+ 	"See comment in primSocketCreateNetwork: with one semaIndex. However you should know that some implementations
+ 	ignore the buffer size and this interface supports three semaphores,  one for open/close/listen and the other two for
+ 	reading and writing"
- 	"See comment in primSocketCreateNetwork: with one semaIndex. However you should know that some implementations ignore the buffer size and this interface supports three semaphores,  one for open/close/listen and the other two for reading and writing"
  
  	<primitive: 'primitiveSocketCreate3Semaphores' module: 'SocketPlugin'>
+ 	primitiveOnlySupportsOneSemaphore := true.
+ 	^ self primSocketCreateNetwork: netType
+ 			type: socketType
+ 			receiveBufferSize: rcvBufSize
+ 			sendBufSize: sendBufSize
+ 			semaIndex: semaIndex!
- 	self primitiveFailed!

Item was added:
+ ----- Method: Socket>>primSocketLocalAddressSize: (in category 'primitives-ipv6') -----
+ primSocketLocalAddressSize: handle
+ 
+ 	<primitive: 'primitiveSocketLocalAddressSize' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was changed:
  ----- Method: Socket>>primSocketReceiveDataAvailable: (in category 'primitives') -----
  primSocketReceiveDataAvailable: socketID
  	"Return true if data may be available for reading from the current socket."
  
  	<primitive: 'primitiveSocketReceiveDataAvailable' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !
- 	self primitiveFailed!

Item was added:
+ ----- Method: Socket>>primSocketRemoteAddressSize: (in category 'primitives-ipv6') -----
+ primSocketRemoteAddressSize: handle
+ 
+ 	<primitive: 'primitiveSocketRemoteAddressSize' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was changed:
  ----- Method: Socket>>remoteAddress (in category 'accessing') -----
  remoteAddress
  
+ 	NetNameResolver useOldNetwork
+ 		ifTrue: [^self primSocketRemoteAddress: socketHandle]
+ 		ifFalse: [^(self primSocketRemoteAddress: socketHandle) asSocketAddress]
- 	^ self primSocketRemoteAddress: socketHandle
  !

Item was added:
+ ----- Method: Socket>>remoteSocketAddress (in category 'ipv6') -----
+ remoteSocketAddress
+ 
+ 	NetNameResolver useOldNetwork
+ 		ifTrue: [^(self primSocketRemoteAddress: socketHandle) asSocketAddress]
+ 		ifFalse: [
+ 			| size addr |
+ 			size := self primSocketRemoteAddressSize: socketHandle.
+ 			addr := SocketAddress new: size.
+ 			self primSocket: socketHandle remoteAddressResult: addr.
+ 			^addr]!

Item was changed:
  ----- Method: Socket>>setOption:value: (in category 'other') -----
  setOption: aName value: aValue 
  	| value |
  	"setup options on this socket, see Unix man pages for values for 
  	sockets, IP, TCP, UDP. IE SO_KEEPALIVE
  	returns an array, element one is the error number
  	element two is the resulting of the negotiated value.
  	See getOption for list of keys"
  
  	(socketHandle == nil or: [self isValid not])
  		ifTrue: [InvalidSocketStatusException signal: 'Socket status must valid before setting an option'].
  	value := aValue asString.
  	aValue == true ifTrue: [value := '1'].
  	aValue == false ifTrue: [value := '0'].
  	^ self primSocket: socketHandle setOption: aName value: value!

Item was changed:
  ----- Method: Socket>>setPeer:port: (in category 'datagrams') -----
  setPeer: hostAddress port: port
  	"Set the default send/recv address."
  
+ 	self primSocket: socketHandle connectTo: hostAddress asByteArray port: port.
- 	self primSocket: socketHandle connectTo: hostAddress port: port.
  !

Item was added:
+ ----- Method: Socket>>waitForConnectionUntil: (in category 'waiting') -----
+ waitForConnectionUntil: deadline
+ 	"Wait up until the given deadline for a connection to be established. Return true if it is established by the deadline, false if not."
+ 
+ 	| status |
+ 	status := self primSocketConnectionStatus: socketHandle.
+ 	[(status = WaitingForConnection) and: [Time millisecondClockValue < deadline]]
+ 		whileTrue: [
+ 			semaphore waitTimeoutMSecs: (deadline - Time millisecondClockValue).
+ 			status := self primSocketConnectionStatus: socketHandle].
+ 
+ 	^ status = Connected
+ !

Item was added:
+ ByteArray variableByteSubclass: #SocketAddress
+ 	instanceVariableNames: ''
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Network-Kernel'!
+ 
+ !SocketAddress commentStamp: '<historical>' prior: 0!
+ I represent a socket (network) address consisting of a host internet address and a port number.  My contents are opaque and cannot be interpreted directly.  See the accessing protocol for methods that retrieve the information I contain.!

Item was added:
+ ----- Method: SocketAddress class>>fromOldByteAddress: (in category 'instance creation') -----
+ fromOldByteAddress: byteArray
+ 	"Use the resolver to find a socket address corresponding to byteArray"
+ 
+ 	| rs addrString addressInfos addressInfo |
+ 	rs := ReadStream on: byteArray.
+ 	addrString := String streamContents: [:strm | 
+ 		[rs atEnd] whileFalse: [
+ 			strm nextPutAll: rs next asString.
+ 			rs atEnd ifFalse: [strm nextPut: $. ]]].
+ 	addressInfos := NetNameResolver addressesForName: addrString.
+ 	addressInfos isEmpty ifTrue: [self error: 'invalid address ', addrString].
+ 	addressInfo := addressInfos
+ 		detect: [:e | e addressFamilyName = #inet4]
+ 		ifNone: [self error: 'no inet4 address for ', addrString].
+ 	^addressInfo socketAddress "first available inet4 interface"
+ !

Item was added:
+ ----- Method: SocketAddress class>>loopback4 (in category 'accessing') -----
+ loopback4
+ 
+ 	^self loopbacks4 first!

Item was added:
+ ----- Method: SocketAddress class>>loopback6 (in category 'accessing') -----
+ loopback6
+ 
+ 	^self loopbacks6 first!

Item was added:
+ ----- Method: SocketAddress class>>loopbacks (in category 'accessing') -----
+ loopbacks
+ 
+ 	^SocketAddressInformation forHost: '' service: '0'
+ 		flags:			0
+ 		addressFamily:	0
+ 		socketType:		0
+ 		protocol:		0!

Item was added:
+ ----- Method: SocketAddress class>>loopbacks4 (in category 'accessing') -----
+ loopbacks4
+ 
+ 	^SocketAddressInformation forHost: 'localhost' service: ''
+ 		flags:			0
+ 		addressFamily:	SocketAddressInformation addressFamilyINET4
+ 		socketType:		0
+ 		protocol:		0!

Item was added:
+ ----- Method: SocketAddress class>>loopbacks6 (in category 'accessing') -----
+ loopbacks6
+ 
+ 	^SocketAddressInformation forHost: '' service: '0'
+ 		flags:			0
+ 		addressFamily:	SocketAddressInformation addressFamilyINET6
+ 		socketType:		0
+ 		protocol:		0!

Item was added:
+ ----- Method: SocketAddress class>>wildcard4 (in category 'accessing') -----
+ wildcard4
+ 
+ 	^self wildcards4 first!

Item was added:
+ ----- Method: SocketAddress class>>wildcard6 (in category 'accessing') -----
+ wildcard6
+ 
+ 	^self wildcards6 first!

Item was added:
+ ----- Method: SocketAddress class>>wildcards (in category 'accessing') -----
+ wildcards
+ 
+ 	^SocketAddressInformation forHost: '' service: '0'
+ 		flags:			SocketAddressInformation passiveFlag
+ 		addressFamily:	0
+ 		socketType:		0
+ 		protocol:		0!

Item was added:
+ ----- Method: SocketAddress class>>wildcards4 (in category 'accessing') -----
+ wildcards4
+ 
+ 	^SocketAddressInformation forHost: '' service: '0'
+ 		flags:			SocketAddressInformation passiveFlag
+ 		addressFamily:	SocketAddressInformation addressFamilyINET4
+ 		socketType:		SocketAddressInformation socketTypeStream
+ 		protocol:		0!

Item was added:
+ ----- Method: SocketAddress class>>wildcards6 (in category 'accessing') -----
+ wildcards6
+ 
+ 	^SocketAddressInformation forHost: '' service: '0'
+ 		flags:			SocketAddressInformation passiveFlag
+ 		addressFamily:	SocketAddressInformation addressFamilyINET6
+ 		socketType:		0
+ 		protocol:		0!

Item was added:
+ ----- Method: SocketAddress>>asByteArray (in category 'converting') -----
+ asByteArray
+ 	"Assuming IPV4, answer a byte array representation of the host number"
+ 	^ ((self hostNumber findTokens: '.')
+ 		collect: [:e | e asInteger]) asByteArray!

Item was added:
+ ----- Method: SocketAddress>>asSocketAddress (in category 'converting') -----
+ asSocketAddress
+ !

Item was added:
+ ----- Method: SocketAddress>>hostName (in category 'accessing') -----
+ hostName
+ 
+ 	| size name |
+ 	NetNameResolver primGetNameInfo: self flags: 0.
+ 	size := NetNameResolver primGetNameInfoHostSize.
+ 	name := String new: size.
+ 	NetNameResolver primGetNameInfoHostResult: name.
+ 	^name!

Item was added:
+ ----- Method: SocketAddress>>hostNumber (in category 'accessing') -----
+ hostNumber
+ 
+ 	| size name |
+ 	NetNameResolver primGetNameInfo: self flags: 1.
+ 	size := NetNameResolver primGetNameInfoHostSize.
+ 	name := String new: size.
+ 	NetNameResolver primGetNameInfoHostResult: name.
+ 	^name!

Item was added:
+ ----- Method: SocketAddress>>port (in category 'primitives') -----
+ port
+ 
+ 	<primitive: 'primitiveSocketAddressGetPort' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: SocketAddress>>port: (in category 'primitives') -----
+ port: anInteger
+ 
+ 	<primitive: 'primitiveSocketAddressSetPort' module: 'SocketPlugin'>
+ 	self primitiveFailed
+ !

Item was added:
+ ----- Method: SocketAddress>>printOn: (in category 'printing') -----
+ printOn: aStream
+ 
+ 	aStream
+ 		nextPutAll: self hostNumber;
+ 		nextPut: $(; nextPutAll: self hostName; nextPut: $);
+ 		nextPut: $,;
+ 		nextPutAll: self serviceNumber;
+ 		nextPut: $(; nextPutAll: self serviceName; nextPut: $)!

Item was added:
+ ----- Method: SocketAddress>>serviceName (in category 'accessing') -----
+ serviceName
+ 
+ 	| size name |
+ 	NetNameResolver primGetNameInfo: self flags: 0.
+ 	size := NetNameResolver primGetNameInfoServiceSize.
+ 	name := String new: size.
+ 	NetNameResolver primGetNameInfoServiceResult: name.
+ 	^name!

Item was added:
+ ----- Method: SocketAddress>>serviceNumber (in category 'accessing') -----
+ serviceNumber
+ 
+ 	| size name |
+ 	NetNameResolver primGetNameInfo: self flags: 1.
+ 	size := NetNameResolver primGetNameInfoServiceSize.
+ 	name := String new: size.
+ 	NetNameResolver primGetNameInfoServiceResult: name.
+ 	^name!

Item was added:
+ Object subclass: #SocketAddressInformation
+ 	instanceVariableNames: 'socketAddress addressFamily socketType protocol'
+ 	classVariableNames: 'AddressFamilyINET4 AddressFamilyINET6 AddressFamilyLocal AddressFamilyUnspecified NumericFlag PassiveFlag ProtocolTCP ProtocolUDP ProtocolUnspecified SocketTypeDGram SocketTypeStream SocketTypeUnspecified'
+ 	poolDictionaries: ''
+ 	category: 'Network-Kernel'!
+ 
+ !SocketAddressInformation commentStamp: '<historical>' prior: 0!
+ I represent a local or remote network service.
+ 
+ Instance Variables
+ 	addressFamily:	<SmallInteger> the address family (unix, inet4, inet6, ...) in which the service address is available.
+ 	protocol:		<SmallInteger> the protocol (tcp, udp, ...) that the service uses.
+ 	socketAddress:	<SocketAddress> the socket address at which the service can be contacted or created.
+ 	socketType:		<SmallInteger> the type (stream, dgram) of the socket that should be created for communication with the service.
+ !

Item was added:
+ ----- Method: SocketAddressInformation class>>addressFamilyINET4 (in category 'accessing') -----
+ addressFamilyINET4
+ 
+ 	^AddressFamilyINET4!

Item was added:
+ ----- Method: SocketAddressInformation class>>addressFamilyINET6 (in category 'accessing') -----
+ addressFamilyINET6
+ 
+ 	^AddressFamilyINET6!

Item was added:
+ ----- Method: SocketAddressInformation class>>addressFamilyLocal (in category 'accessing') -----
+ addressFamilyLocal
+ 
+ 	^AddressFamilyLocal!

Item was added:
+ ----- Method: SocketAddressInformation class>>addressFamilyUnspecified (in category 'accessing') -----
+ addressFamilyUnspecified
+ 
+ 	^AddressFamilyUnspecified!

Item was added:
+ ----- Method: SocketAddressInformation class>>forHost:service:flags:addressFamily:socketType:protocol: (in category 'instance creation') -----
+ forHost: hostName service: servName flags: flags addressFamily: family socketType: type protocol: protocol
+ 
+ 	| result addr |
+ 	NetNameResolver initializeNetwork.
+ 	NetNameResolver primGetAddressInfoHost: hostName service: servName flags: flags family: family type: type protocol: protocol.
+ 	result := OrderedCollection new.
+ 	[(addr := NetNameResolver nextSocketAddressInformation) notNil] whileTrue: [result add: addr].
+ 	^result!

Item was added:
+ ----- Method: SocketAddressInformation class>>initialize (in category 'class initialization') -----
+ initialize			"SocketAddressInformation initialize"
+ 
+ 	NumericFlag := 1.
+ 	PassiveFlag := 2.
+ 	AddressFamilyUnspecified := 0.
+ 	AddressFamilyLocal := 1.
+ 	AddressFamilyINET4 := 2.
+ 	AddressFamilyINET6 := 3.
+ 	SocketTypeUnspecified := 0.
+ 	SocketTypeStream := 1.
+ 	SocketTypeDGram := 2.
+ 	ProtocolUnspecified := 0.
+ 	ProtocolTCP := 1.
+ 	ProtocolUDP := 2.!

Item was added:
+ ----- Method: SocketAddressInformation class>>numericFlag (in category 'accessing') -----
+ numericFlag
+ 
+ 	^NumericFlag!

Item was added:
+ ----- Method: SocketAddressInformation class>>passiveFlag (in category 'accessing') -----
+ passiveFlag
+ 
+ 	^PassiveFlag!

Item was added:
+ ----- Method: SocketAddressInformation class>>protocolTCP (in category 'accessing') -----
+ protocolTCP
+ 
+ 	^ProtocolTCP!

Item was added:
+ ----- Method: SocketAddressInformation class>>protocolUDP (in category 'accessing') -----
+ protocolUDP
+ 
+ 	^ProtocolUDP!

Item was added:
+ ----- Method: SocketAddressInformation class>>protocolUnspecified (in category 'accessing') -----
+ protocolUnspecified
+ 
+ 	^ProtocolUnspecified!

Item was added:
+ ----- Method: SocketAddressInformation class>>socketTypeDGram (in category 'accessing') -----
+ socketTypeDGram
+ 
+ 	^SocketTypeDGram!

Item was added:
+ ----- Method: SocketAddressInformation class>>socketTypeStream (in category 'accessing') -----
+ socketTypeStream
+ 
+ 	^SocketTypeStream!

Item was added:
+ ----- Method: SocketAddressInformation class>>socketTypeUnspecified (in category 'accessing') -----
+ socketTypeUnspecified
+ 
+ 	^SocketTypeUnspecified!

Item was added:
+ ----- Method: SocketAddressInformation class>>withSocketAddress:family:type:protocol: (in category 'instance creation') -----
+ withSocketAddress: socketAddress family: family type: type protocol: protocol
+ 
+ 	^self new initSocketAddress: socketAddress family: family type: type protocol: protocol!

Item was added:
+ ----- Method: SocketAddressInformation>>addressFamilyName (in category 'accessing') -----
+ addressFamilyName
+ 
+ 	^#(unspecified local inet4 inet6) at: addressFamily + 1!

Item was added:
+ ----- Method: SocketAddressInformation>>connect (in category 'circuit setup') -----
+ connect
+ 
+ 	| sock |
+ 	socketType == SocketTypeStream ifFalse: [^nil].
+ 	sock := Socket newTCP: addressFamily.
+ 	sock connectTo: socketAddress.
+ 	sock waitForConnectionFor: Socket standardTimeout
+ 		ifTimedOut: [ConnectionTimedOut signal: 'Cannot connect to ', self printString].
+ 	^sock!

Item was added:
+ ----- Method: SocketAddressInformation>>initSocketAddress:family:type:protocol: (in category 'initialize-release') -----
+ initSocketAddress: aSocketAddress family: familyInteger type: typeInteger protocol: protocolInteger
+ 
+ 	socketAddress := aSocketAddress.
+ 	addressFamily := familyInteger.
+ 	socketType := typeInteger.
+ 	protocol := protocolInteger.!

Item was added:
+ ----- Method: SocketAddressInformation>>listenWithBacklog: (in category 'circuit setup') -----
+ listenWithBacklog: backlog
+ 
+ 	| sock |
+ 	(socketType == SocketTypeStream and: [protocol == ProtocolTCP]) ifFalse: [self error: 'cannot listen'].
+ 	sock := Socket newTCP: addressFamily.
+ 	sock bindTo: socketAddress.
+ 	sock listenWithBacklog: 5.
+ 	^sock!

Item was added:
+ ----- Method: SocketAddressInformation>>printOn: (in category 'printing') -----
+ printOn: aStream
+ 
+ 	aStream
+ 		print: socketAddress;
+ 		nextPut: $-; nextPutAll: self addressFamilyName;
+ 		nextPut: $-; nextPutAll: self socketTypeName;
+ 		nextPut: $-; nextPutAll: self protocolName!

Item was added:
+ ----- Method: SocketAddressInformation>>protocolName (in category 'accessing') -----
+ protocolName
+ 
+ 	^#(unspecified tcp udp) at: socketType + 1!

Item was added:
+ ----- Method: SocketAddressInformation>>socketAddress (in category 'accessing') -----
+ socketAddress
+ 
+ 	^socketAddress!

Item was added:
+ ----- Method: SocketAddressInformation>>socketTypeName (in category 'accessing') -----
+ socketTypeName
+ 
+ 	^#(unspecified stream dgram) at: socketType + 1!

Item was changed:
  ----- Method: SocketStream class>>openConnectionToHost:port: (in category 'instance creation') -----
  openConnectionToHost: hostIP port: portNumber
+ 	| socket |
+ 	socket := Socket new.
+ 	socket connectTo: hostIP port: portNumber.
+ 	^self on: socket!
- 	^ self openConnectionToHost: hostIP port: portNumber timeout: Socket standardTimeout!



More information about the Packages mailing list