'From iSqueak3.6 of ''14 December 2004'' [latest update: #5430] on 27 December 2004 at 6:40:02 pm'! "Change Set: socketFixes Date: 27 December 2004 Author: Michael Rueger, Avi Bryant, Masashi Umezawa Fixes the off-by-one in SocketStream>>upToAll: and adds some checks to the socket connection methods"! !ConnectionQueue methodsFor: 'private' stamp: 'mu 8/9/2003 14:58'! 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" 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]. [true] whileTrue: [ socket isValid ifFalse: [ "socket has stopped listening for some reason" socket destroy. (Delay forMilliseconds: 10) wait. ^self listenLoop ]. newConnection _ socket waitForAcceptFor: 10. (newConnection notNil and:[newConnection isConnected]) ifTrue: [accessSema critical: [connections addLast: newConnection]. newConnection _ nil]. self pruneStaleConnections]. ! ! !PositionableStream methodsFor: 'positioning' stamp: 'avi 12/5/2004 17:41'! positionOfSubCollection: subCollection ifAbsent: exceptionBlock "Return a position such that that element at the new position equals the first element of sub, and the next elements equal the rest of the elements of sub. Begin the search at the current position. If no such match is found, answer the result of evaluating argument, exceptionBlock." | pattern startPosition currentPosition | pattern _ ReadStream on: subCollection. startPosition := self position. [pattern atEnd] whileFalse: [self atEnd ifTrue: [^exceptionBlock value]. self next = pattern next ifFalse: [pattern reset]]. currentPosition := self position. self position: startPosition. ^pattern atEnd ifTrue: [currentPosition + 1 - subCollection size] ifFalse: [exceptionBlock value]! ! !Socket methodsFor: 'receiving' stamp: 'mu 8/9/2003 18:04'! receiveAvailableDataInto: buffer startingAt: startIndex "Receive all available data into the given buffer and return the number of bytes received. Note the given buffer may be only partially filled by the received data. Do not wait for data." | bufferPos bytesRead | bufferPos := startIndex. [self dataAvailable and: [bufferPos-1 < buffer size]] whileTrue: [ bytesRead := self receiveSomeDataInto: buffer startingAt: bufferPos. bufferPos := bufferPos + bytesRead]. ^bufferPos - startIndex! ! !Socket methodsFor: 'waiting' stamp: 'mu 8/9/2003 15:17'! waitForAcceptFor: timeout "Wait and accept an incoming connection. Return nil if it falis" [self waitForConnectionFor: timeout] on: ConnectionTimedOut do: [:ex | ^nil]. ^self isConnected ifTrue:[self accept] ! ! !SocketStream methodsFor: 'stream in' stamp: 'avi 12/5/2004 17:42'! upToAll: delims "Answer a subcollection from the current access position to the occurrence (if any, but not inclusive) of aCollection. If aCollection is not in the stream, answer the entire rest of the stream." "Optimized version using the positionOfSubCollection:. Based on a suggestion by miso" | searchBuffer index nextStartOfSearch currentContents | searchBuffer _ ReadWriteStream on: (String new: 1000). [nextStartOfSearch _ (searchBuffer position - delims size) max: 0. searchBuffer nextPutAll: self inStream upToEnd. self resetInStream. searchBuffer position: nextStartOfSearch. index _ searchBuffer positionOfSubCollection: delims. index = 0 and: [self atEnd not]] whileTrue: [self receiveData]. currentContents := searchBuffer contents. ^index = 0 ifTrue: [currentContents] ifFalse: [ self pushBack: (currentContents copyFrom: index + delims size to: currentContents size). currentContents copyFrom: 1 to: (0 max: index-1)]! !