eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'Socket':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: Socket


Inheritance:

   Object
   |
   +--Stream
      |
      +--PeekableStream
         |
         +--PositionableStream
            |
            +--WriteStream
               |
               +--ReadWriteStream
                  |
                  +--ExternalStream
                     |
                     +--NonPositionableExternalStream
                        |
                        +--Socket

Package:
stx:libbasic2
Category:
Streams-External
Version:
rev: 1.371 date: 2019/06/06 23:45:51
user: cg
file: Socket.st directory: libbasic2
module: stx stc-classLibrary: libbasic2
Author:
Claus Gittinger

Description:


This class provides access to sockets for interprocess communication.

Currently, only IP and UNIX domain sockets are really fully
tested and supported.
Code for appletalk is included, but was never tested ...
More may be added in the future.
(the code is prepared for things like SNA or decNet;
 however, right now, this code is empty and needs a little work.
 Implementing those is pretty straightforward, once the address
 data structures are known.)

Due to historic reasons (I started this class, before I got hold of some
code using ST-80 Sockets i.e. RemoteInvocation), there is some old interface
which is still supported.
This may vanish; use the #family:type: or #newTCPxxx and #newUDPxxx interfaces,
together with the bind/listen and accept calls,
which are meant to be compatible to ST-80's UnixSocketAccessor interface.

TODO: cleanup historic leftovers,
      change to raise more signals on errors.


Class protocol:

Compatibility-ST80
o  family: domainSymbol type: typeSymbol
create a socket for domain and type - ST80 simply uses a different name.
Domain must be one of the symbols: #inet, #unix, #appletalk or #ns;
Type must be #stream, #datagram or #raw.

usage example(s):

     Socket family:#AF_INET type:#stream
     Socket family:#AF_INET type:#datagram
     Socket family:#AF_UNIX type:#stream

o  getHostname
return the computer's hostname string

o  sockStream
return the type code for stream sockets

Compatibility-Squeak
o  deadlineSecs: seconds

o  initializeNetwork
intentionally left blank here

o  openConnectionToHostNamed: hostName port: portNr

o  standardDeadline
a standard timeout in seconds for connection setup;
not really used in ST/X code (but by some code ported from squeak)

o  standardTimeout
a standard timeout in seconds for transfers;
not really used in ST/X code (but by some code ported from squeak)

o  wildcardPort

Compatibility-VW
o  AF_INET

o  SOCK_STREAM

Signal constants
o  brokenConnectionSignal
return the signal used to tell broken connections.
Since in unix, this is the same as the broken pipe signal,
return that one.
(for other Operatingsystems, this may change ..)

o  invalidArgumentsSignal
dummy for compatibility

debugging
o  debug: aBoolean
turn on/off internal debugprints.
This method is for ST/X debugging only and
may be removed in later versions

usage example(s):

     Socket debug:true
     Socket debug:false

defaults
o  defaultIpDomainForConnect
answer the domain used to look up host names for connect:
#AF_INET use only IPv4
#AF_INET6 use only IPv6
nil use both IPv4 and IPv6

instance creation
o  bindTo: aSocketAddress type: aTypeSymbol
create a socket for a specific type
and bind it to aSocketAddress.
Type must be:
#stream, #datagram or #raw

Neither connect nor connect-wait is done.

usage example(s):

	Socket bindTo:(IPSocketAddress anyHost port:8081) type:#stream.
	Socket bindTo:(IPv6SocketAddress anyHost port:8081) type:#datagram.

o  domain: domainSymbol type: type
create a socket for domain and type -
neither any connect nor binding is done.
Domain must be one of the symbols:
#inet, #unix, #appletalk, #decnet, #xns, ...;
Type must be:
#stream, #datagram or #raw

XXX: currently only the #AF_INET and #AF_INET6 and #AF_UNIX domains are supported

usage example(s):

     Socket domain:#AF_INET type:#stream
     Socket domain:#AF_INET type:#datagram
     Socket domain:#AF_INET6 type:#stream
     Socket domain:#AF_INET6 type:#datagram
     Socket domain:#AF_UNIX type:#stream

o  newIPv6
create an IPv6 socket - no binding or other setup is done,
neither connect nor connect-wait is done.

usage example(s):

      Socket newIPv6

o  newIPv6: portNrOrServiceName
create an IPv6 socket for a service -
neither connect nor connect-wait is done.

usage example(s):

     (Socket newIPv6:9996).

     test (eval the code below, then open a browser on (replace by your own IPv6 address)
	http://[2003:a:e4d:bb01:a17f:9312:54cb:fed7]:9997/

     (Socket newIPv6:9997)
	listenFor:1;
	readWait;
	accept.

o  newTCP
create a TCP socket - no binding or other setup is done,
neither connect nor connect-wait is done.

usage example(s):

      Socket newTCP

o  newTCP: portNrOrServiceName
create a TCP socket for a service -
neither connect nor connect-wait is done.

usage example(s):

	Socket newTCP:'http-alt'.
	Socket newTCP:9996.

o  newTCPclientToAddress: aHostAddress port: aService
create a new TCP client socket connecting to a service.
Return a socket instance if ok, nil on failure.
Block until a connection is established (but only the current thread;
not the whole smalltalk).
See also: #newTCPclientToAddress:port:withTimeout:

o  newTCPclientToAddress: aSocketAddressOrByteArray port: aService withTimeout: milliSecondsOrTimeDuration
create a new TCP client socket connecting to a service.
Return a socket instance if ok, nil on failure.
If the millis arg is nonNil, stop trying to connect after that many milliseconds
and return nil.

o  newTCPclientToAddress: aSocketAddress withTimeout: milliSecondsOrTimeDuration
create a new TCP client socket connecting to a service.
Return a socket instance if ok, nil on failure.
If the millis arg is nonNil, stop trying to connect after that many milliseconds
and return nil.

usage example(s):

	self newTCPclientToAddress:(IPv6SocketAddress hostName:'www.exept.de' port:80) withTimeout:nil

o  newTCPclientToHost: hostNameOrAddress port: aPortOrServiceName
create a new TCP client socket connecting to a service.
If hostNameOrAddress is a string, try all the resolved addresses regardless
whether for IPv4 or IPv6.
Return a socket instance if ok, nil on failure.
Block until a connection is established (but only the current thread;
not the whole smalltalk).
See also: #newTCPclientToHost:port:withTimeout:

usage example(s):

      Socket newTCPclientToHost:'www.exept.de' port:'https'

o  newTCPclientToHost: hostNameOrAddress port: aPortOrServiceName domain: aDomainSymbolOrNil withTimeout: milliSecondsOrTimeDuration
create a new TCP client socket connecting to a service on hostNameOrAddress.
If hostNameOrAddress is a string, try all the resolved addresses.
Return a socket instance if ok, nil on failure.
Set aDomainSymbolOrNil to #AF_INET of #AF_INET6 to connect via a defined protocol.
Set aDomainSymbolOrNil to nil, to try all protocols.
If the milliSecondsOrTimeDuration arg is nonNil, stop trying to connect after that many milliSecondsOrTimeDurationeconds
and return nil.

o  newTCPclientToHost: hostNameOrAddress port: aPortOrServiceName withTimeout: milliSecondsOrTimeDuration
create a new TCP client socket connecting to a service on hostNameOrAddress.
If hostNameOrAddress is a string, try all the resolved addresses regardless
whether for IPv4 or IPv6.
Return a socket instance if ok, nil on failure.
If the millis arg is nonNil, stop trying to connect after that many milliseconds
and return nil.

o  newTCPserverAtAnonymousPort
create a new TCP server socket providing service on
a new anonymous port. The portNr is assigned by the OS.

o  newTCPserverAtPort: portNrOrServiceName
create a new TCP server socket providing service.

o  newUDP
create a UDP socket - no binding or other setup is done,
neither connect nor connect-wait is done.

usage example(s):

Socket newUDP

o  newUDP: aServiceOrNil
create a UDP socket for a service -
neither connect nor connect-wait is done.

usage example(s):

	Socket newUDP:4444.
	Socket newUDP:'activesync'.

o  newUDPserverAtPort: aService
create a new UDP server socket providing service.

o  newUNIX
create a UNIX domain socket - no binding or other setup is done,
neither connect nor connect-wait is done.
If the system does not support unix domain sockets (i.e. VMS or MSDOS),
return nil.

usage example(s):

     Socket newUNIX

o  newUNIXclientTo: pathName
create a new UNIX client socket connecting to a pathname.
Return a socket instance if ok, nil on failure.
Block until a connection is established (but only the current thread;
not the whole smalltalk).
If the system does not support unix domain sockets (i.e. VMS or MSDOS),
return nil.
See also: #newUNIXclientTo:withTimeout:

o  newUNIXclientTo: pathName withTimeout: milliSecondsOrTimeDuration
create a new UNIX client socket connecting to a pathname.
Return a socket instance if ok, nil on failure.
If the millis arg is nonNil, stop trying to connect after that many milliseconds
and return nil.
If the system does not support unix domain sockets (i.e. VMS or MSDOS),
return nil.

usage example(s):

	Socket newUNIXclientTo:'/tmp/foo'

	[
	    Socket newUNIXclientTo:'/tmp/foo'
	] on:SocketErrorNotification do:[:ex|
	    ex halt.
	]

o  newUNIXserverAt: pathName
create a new UNIX server socket providing service at a pathname.
If the system does not support unix domain sockets (i.e. VMS or MSDOS),
return nil.

obsolete
o  connectTo: service on: host
standard & easy client setup:
create new client tcp socket, bind and connect;
return the socket.
The thread blocks (interruptable), until the connection is established.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  networkLongOrderIsMSB
return the well known fact, that network byte order is most significant byte first

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  networkShortOrderIsMSB
return the well known fact, that network byte order is most significant byte first

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  provide: aService
standard & easy server setup:
create a new TCP server socket providing a service.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

obsolete host queries
o  appletalkAddressOfHost: aHostName
return the APPLETALK address for a hostname as a byteArray,
where the network bytes come first (no matter what the local byteorder is)
followed by the node byte.
If the host is unknown, return nil.
This is the reverse operation to #hostWithAppletalkAddress:.
WARNING: untested code - I have no appletalk to test this.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  hostWithAppletalkAddress: addrByteArray
return the hostname for an APPLETALK address.
The address is supposed to be a byteArray consisting of 3 bytes,
the network bytes come first (no matter what the local byteorder is).
The last byte is the node number.
Nil is returned for an unknown host or if it's not an appletalk host.
This is is the reverse operation to #appletalkAddressOfHost:.
WARNING: untested code - I have no appletalk to test this.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  hostWithIpAddress: addrByteArray
return the hostname for an IP (internet-) address.
The address is supposed to be a byteArray consisting of 4 bytes,
the network bytes come first (no matter what the local byteorder is).
Nil is returned for an unknown host or if it's not an internet host.
This is the reverse operation to #ipAddressOfHost:.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  hostWithIpV6Address: addrByteArray
return the hostname for an IPv6 (internet-) address.
The address is supposed to be a byteArray consisting ??? bytes,
the network bytes come first (no matter what the local byteorder is).
Nil is returned for an unknown host or if it's not an internet host.
This is the reverse operation to #ipV6AddressOfHost:.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  ipAddressOfHost: aHostName
return the IP (internet-) number for a hostname as a byteArray,
where the network bytes come first (no matter what the cpus byteOrder is).
If the host is unknown, return nil.
This is the reverse operation to #hostWithIpAddress:.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  ipV6AddressOfHost: aHostName
return the IPv6 (internet-) number for a hostname as a byteArray,
where the network bytes come first (no matter what the cpus byteOrder is).
If the host is unknown, return nil.
This is the reverse operation to #hostWithIpV6Address:.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

queries
o  peerFromDomain: domain name: peerName port: port

o  peerNameFromDomain: domain peer: peer

o  portOfService: aNameOrNumber
returns the port-number for a given IP-service
or nil if no such service exists;
- used to convert service names to portNumbers

usage example(s):

     Socket portOfService:'finger'
     Socket portOfService:'nntp'
     Socket portOfService:'echo'
     Socket portOfService:'snmp'

o  portOfService: aNameOrNumber protocol: aProtocol
returns the port-number for a given IP-service
or nil if no such service exists;
- used to convert service names to portNumbers

usage example(s):

     Socket portOfService:'echo' protocol:'udp'
     Socket portOfService:'echo' protocol:'tcp'

o  protocolOfService: aNameOrNumber
returns the protocol (as string) for a given IP-service
or nil if no such service exists.

usage example(s):

     Socket protocolOfService:'finger'
     Socket protocolOfService:'nntp'
     Socket protocolOfService:'xxx'
     Socket protocolOfService:79
     Socket protocolOfService:'snmp'

o  socketAddressClassForDomain: domain
self socketAddressClassForDomain:#AF_INET
self socketAddressClassForDomain:#AF_UNIX

o  supportedProtocolFamilies
return a collection of supported protocol families.
This list specifies what the Socket class supports -
socket creation may still fail, if your system was built
without it.

usage example(s):

     Socket supportedProtocolFamilies

o  typeOfProtocol: aProtocol
given a protocols name (i.e. tcp, udp etc) return the connection type.
This method needs more ... - or is there a way to get this from the system ?

usage example(s):

     Socket typeOfProtocol:'tcp'
     Socket typeOfProtocol:'ucp'
     Socket typeOfProtocol:(Socket protocolOfService:'nntp')
     Socket typeOfProtocol:(Socket protocolOfService:'echo')


Instance protocol:

Compatibility-Dolphin
o  setReceiveTimeout: milliseconds

o  setSendTimeout: milliseconds

Compatibility-ST80
o  acceptNonBlock

o  ioConnection

o  notReadySignal
ST-80 mimicry.
for now - this is not yet raised

o  readAppendStream
ST-80 mimicry.
In ST-80, socket is not a stream, but refers to one.
ST-80 code therefore uses 'Socket readWriteStream' to access
the actual stream.
In ST/X, sockets inherit from stream, so
this method returns the receiver, for transparency

o  readStream
ST-80 mimicry.
In ST-80, socket is not a stream, but refers to one.
ST-80 code therefore uses 'Socket readStream' to access
the actual stream.
In ST/X, sockets inherit from stream, so
this method returns the receiver, for transparency

o  writeStream
ST-80 mimicry.
In ST-80, socket is not a stream, but refers to one.
ST-80 code therefore uses 'Socket writeStream' to access
the actual stream.
In ST/X, sockets inherit from stream, so
this method returns the receiver, for transparency

Compatibility-Squeak
o  address

o  bindTo: interfaceAddr port: portNr
( an extension from the stx:libcompat package )

o  connectToHostNamed: hostName port: portNr

o  dataAvailable

o  destroy

o  listenOn: aPortNr

o  listenOn: aPortNr backlogSize: aNumber

o  localAddress
( an extension from the stx:libcompat package )
^ self address

o  noTimeout
disable timeouts - dummy for now

o  peerName
return my peer (i.e. ipAddr + port);
May return nil if not yet setup completely.

o  primSocketLocalPort: aSocket
( an extension from the stx:libcompat package )

o  receiveUDPDataInto: aDataBuffer
( an extension from the stx:libcompat package )
squeak returns the result in a vector

o  sendData: aStringOrByteArray
Send all of the data in the given array, even if it requires multiple calls to send it all.
Return the number of bytes sent.

o  sendUDPData: bytes toHost: aHostAddr port: portNr
( an extension from the stx:libcompat package )

o  setOption: optionName value: optionValue
( an extension from the stx:libcompat package )
Not all OperatingSystems offer this functionality for any option
(returns false, if unsupported)

o  socketHandle
( an extension from the stx:libcompat package )

o  waitForConnectionUntil: aTimestamp
return true if connected

o  waitForData
( an extension from the stx:libcompat package )

o  waitForDataForMsecs: timeout ifClosed: closedBlock ifTimedOut: timedOutBlock
( an extension from the stx:libcompat package )
Seconds resolution is way too much for for instance, UDP sockets running on local network, use this when timeouts > 1 sec is desirable

o  waitForDataIfClosed: aBlock
( an extension from the stx:libcompat package )

accepting connections
o  accept
create a new TCP socket from accepting on the receiver.
This method will suspend the current process if no connection is waiting.
For ST-80 compatibility

o  blockingAccept
create a new TCP socket from accepting on the receiver.
This method will suspend the smalltalk image with all smalltalk processes if no connection is waiting.
For ST-80 compatibility

binding
o  bindAnonymously
bind to any address. A free port will be allocated.
Our own socket address will be determined after connection set up.
This is the default after the socket has been created

usage example(s):

      self newTCP bindAnonymously; listenFor:1; yourself
      self newTCP bindAnonymously; port

o  bindAnonymouslyToAddress: aSocketAddress
bind to address addressString.
A free port will be allocated

usage example(s):

      self newTCP bindAnonymouslyToAddress:IPSocketAddress localHost; listenFor:1; yourself

o  bindTo: aSocketAddress
ST80 compatible bind, expecting a socketAddress argument.
The socketAddress object (an instance of SocketAddress)
is supposed to respond to #portOrName and #address requests.

o  bindTo: portNrOrNameString address: addressString
Old interface: bind the socket to an address
- returns true if ok, false otherwise.
Notify with a SocketErrorNotification on error.

The interpretation of hostOrPathNameOrSocketAddrOrNil portNrOrName depends on the domain:
Best use a SocketAddress
For backward compatibility:
AF_INET domain can also use (4byte) byteArray like internet numbers,
AF_UNIX domain cab use pathname strings.

o  bindTo: portNrOrNameOrNil address: hostOrPathNameOrSocketAddrOrNil reuseAddress: reuse
Old interface: bind the socket to an address
Notify with a SocketErrorNotification on error.
- returns true if ok, false otherwise.

The interpretation of hostOrPathNameOrSocketAddrOrNil portNrOrName depends on the domain:
Best use a SocketAddress
For backward compatibility:
AF_INET domain can also use (4byte) byteArray like internet numbers,
AF_UNIX domain can use pathname strings.

The reuse boolean argument controls if the SO_REUSEADDR socket option
is to be set (to avoid the 'bind: address in use' error).

usage example(s):

     (Socket domain:#'AF_INET' type:#stream)
	 bindTo:2144 address:nil; yourself

o  bindTo: aSocketAddress reuseAddress: reuse
Bind the socket to aSocketAddress - returns true if ok, false otherwise.
Notify with a SocketErrorNotification on error.

The reuse boolean argument controls if the SO_REUSEADDR socket option
is to be set (to avoid the 'bind: address in use' error).

You can bind to nil to bind to anyHost and assign a random port.

usage example(s):

     (Socket domain:#'AF_INET' type:#stream)
	bindTo:(IPSocketAddress anyHost port:445) reuseAddress:false;
	yourself.

     (Socket domain:#'AF_INET' type:#stream)
	bindTo:139 reuseAddress:false;
	yourself.

     (Socket domain:#'AF_INET6' type:#stream)
	bindTo:nil reuseAddress:false;
	yourself.

     (Socket domain:#'AF_INET' type:#stream)
	bindTo:(IPSocketAddress localHost port:2122) reuseAddress:false;
	yourself.

     (Socket domain:#'AF_UNIX' type:#stream)
	bindTo:nil reuseAddress:false;
	yourself.

o  listenFor: aNumber
start listening; return true if ok, false on error.
Notify with a SocketErrorNotification on error.
aNumber is the number of connect requests, that may be queued on the socket

usage example(s):

       [
	   |sock|
	   sock := Socket newTCP.
	   sock listenFor:1.
	   sock
       ] on:SocketErrorNotification do:[:ex|
	   ex halt.
       ].

closing
o  abortAndClose
immediately abort the connection:
discard buffered data and close the stream

o  shutDown
shutDown (initiate a graceful close)
and close (free the filedescriptor) the socket.
The close will return immediately and buffered data will be sent in the
background, unless you set linger

o  shutDownInput
shutDown the input side of the socket.
Any read on the socket will signal end-of-file from now on.
The other side MAY be informed, that no more data will be accepted
(e.g. setting the TCP-Windowsize to 0)

o  shutDownOutput
shutDown the output side of the socket.
Any write to the socket will signal end-of-file from now on.
An orderly release (TCP FIN) will be initiated after the last buffered data
has been sent, so the other side will get a end-of-file condition eventually.
If you set linger > 0, the operation will wait until buffered data
has been delivered to the peer.
Otherwise the operation returns immediately.

connecting
o  connectTo: aSocketAddress

o  connectTo: hostOrPathName port: portNrOrName
Backward compatibility connect; connect to port, portNrOrNameOrNil on host, hostOrPathNameOrSocketAddr.
For backward compatibility, hostOrPathNameOrSocketAddr may be also a string or a byteArray,
but it is recommended to pass SocketAddress instances.

Return true if ok, false otherwise.
The current process will block (but not the whole Smalltalk) until the connection is established.
See also: #connectTo:port:withTimeout: for a somewhat nicer interface.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  connectTo: hostOrPathNameOrSocketAddr port: portNrOrNameOrNil withTimeout: milliSecondsOrTimeDuration
Backward compatibility connect; connect to port, portNrOrNameOrNil on host, hostOrPathNameOrSocketAddr.
For backward compatibility, hostOrPathNameOrSocketAddr may be also a string or a byteArray,
but it is recommended to pass SocketAddress instances.

Return true if ok, false otherwise.
Notify with a SocketErrorNotification on error.

The current process will block (but not the whole Smalltalk) until the connection is established,
or milliSecondsOrTimeDuration milliseconds have passed.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  connectTo: aSocketAddress withTimeout: milliSecondsOrTimeDuration
Connect to a SocketAddress.

Return true if ok, false otherwise.
Notify with a SocketErrorNotification on error.

The current process will block (but not the whole Smalltalk) until the connection is established,
or timeout milliseconds have passed.

datagram transmission
o  receiveBuffer: aDataBuffer start: startIndex for: nBytes
receive data
Return the number of bytes received.
The thread blocks until data arrives - you may want to wait before
receiving, using #readWait or #readWaitWithTimeout:.

o  receiveFrom: aSocketAddress buffer: aDataBuffer
receive datagramm data - put address of originating host into
aSocketAddress, data into aDataBuffer.
aDataBuffer must be ByteArray-like.
For backward compatibility, aSocketAddress may be a non-SocketAddress;
then, it must be a byteArray with appropriate size for the addressBytes.

Return the number of bytes received.
The thread blocks until data arrives - you may want to wait before
receiving, using #readWait or #readWaitWithTimeout:.

o  receiveFrom: aSocketAddress buffer: aDataBuffer start: startIndex for: nBytes
Modified (format): / 21-03-2018 / 19:32:27 / stefan

o  receiveFrom: aSocketAddress buffer: aDataBuffer start: startIndex for: nBytes flags: flags
receive datagramm data
- put address of originating host into aSocketAddress, data into aDataBuffer.
aDataBuffer must be ByteArray-like.
For backward compatibility, aSocketAddress may be a non-SocketAddress;
then, it must be a byteArray with appropriate size for the addressBytes.

Return the number of bytes received.
The thread blocks until data arrives - you may want to wait before
receiving, using #readWait or #readWaitWithTimeout:.

o  sendBuffer: aDataBuffer start: startIndex for: nBytes flags: flags
send data. aDataBuffer be ByteArray-like.
Return the number of bytes transmitted, or a negative number on error.

o  sendTo: aSocketAddress buffer: buffer
send datagramm data - fetch address of destination host from
aSocketAddress, data from aDataBuffer.
aDataBuffer must be ByteArray-like.
aSocketAddress must be a valid SocketAddress for my domain
(i.e. for IPv4, an IPSocketAddress).
For backward compatibility, a ByteArray is still supported in aSocketAddress
(i.e. for IPv4, a 4-byte byteArray).
Return the number of bytes transmitted.

o  sendTo: aSocketAddress buffer: buffer start: startIndex for: count
send datagramm data - fetch address of destination host from
aSocketAddress, data from aDataBuffer.
aDataBuffer must be ByteArray-like.
aSocketAddress must be a valid SocketAddress for my domain
(i.e. for IPv4, an IPSocketAddress).
For backward compatibility, a ByteArray is still supported in aSocketAddress
(i.e. for IPv4, a 4-byte byteArray).
Return the number of bytes transmitted.

o  sendTo: aSocketAddress buffer: aDataBuffer start: startIndex for: nBytes flags: flags
send datagramm data - fetch address of destination host from
aSocketAddress, data from aDataBuffer starting at startIndex,
sending count bytes.
aDataBuffer must be ByteArray-like.
aSocketAddress must be a valid SocketAddress for my domain
(i.e. for IPv4, an IPSocketAddress).
For backward compatibility, a ByteArray is still supported in aSocketAddress
(i.e. for IPv4, a 4-byte byteArray).
Return the number of bytes transmitted.

error reporting
o  reportError: osErrorNumber
report an error to the initiator of a Socket operation.
We raise a notification for newer code, and also
return false for old code not catching the notification.

finalization
o  finalize
do an abortive release - discard buffered data

initialization
o  initialize
transparent

low level
o  getSocketAdress
BAD SPELLING, of #getSocketAddress, kept for compatibility with swazoo

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  getSocketError
get the SO_ERROR form the socket, which indicates the
result of an asynchronous operation

o  listenWithBacklog: aNumber
same as listenFor: - backward compatibility with old ST/X

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  primAcceptOn: aServerSocket blocking: blocking
accept a connection on a server port (created with:'Socket>>newTCP:')
usage is: (Socket basicNew acceptOn:(Socket newTCP:9999)).
Return the true if ok; false if not.
Notify with a SocketErrorNotification on error.

If blocking is true, the accept() syscall (and the whole smalltalk image)
will block, until a connection is accepted.
If blocking is false, this call will return immediately, if there is no connection pending.

o  setSocketOption: option argument: arg1 argument: arg2

o  shutdown: howNum
shutDown the socket - inform it that no more I/O will be performed.
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.

printing & storing
o  printOn: aStream
(comment from inherited method)
append a user printed representation of the receiver to aStream.
The format is suitable for a human - not meant to be read back.

queries
o  domain
return the sockets addressing domain (i.e. #AF_INET, #AF_INET6, #AF_UNIX, ...)

o  getFullPeerAddress
implemented for swazoo project (primitive code can't be loaded as extension)
Answer my own address (I am bound to this address).
Note that this address may change after a connect or accept.

o  getFullSocketAddress
implemented for swazoo project (primitive code can't be loaded as extension)
Answer my own address (I am bound to this address).
Note that this address may change after a connect or accept.

o  getName
return the name; here, we return the ports name

o  getPeer
ST-80 compatibility: return an IPSocketAddress instance representing
my hostname/port combination.
If you are interested in the hostname, use getPeerName directly.

o  getPeerName
return the peer name; that's the hostname (or dotted name) of the
partners host after an accept.

o  getSocketAddress
implemented for swazoo project primitive code cant load as extension
answer my own address (I am bound to this address).
Note that this address may change after connect or accept.

o  isActive
return true, if the receiver has a connection or is bound or listening

o  isConnected
return true, if the receiver has a connection

o  port
return the port number (or name for unix-sockets) to which the socket is bound
- so this is the local port.

usage example(s):

port := self getFullSocketAddress port.

o  socketAddressClass
get the matching SocketAddress class for this socket

o  type
return the sockets connection type (i.e. #datagram, #stream etc)

socket setup
o  domain: domainArg type: typeArg
set up socket with domain and type.
This is a low level entry; no binding, listening or connect
is done. Both arguments must be symbols from one of
#AF_INET, #AF_INET6, #AF_UNIX ... and #stream, #datagram, #raw resp.

o  domain: domainArg type: typeArg protocol: protocolNumber
set up socket with domain, type and protocol number.
This is a low level entry; no binding, listening or connect
is done. Both arguments must be symbols from one of
#AF_INET, #AF_INET6, #AF_UNIX ... and #stream, #datagram, #raw resp.

usage example(s):

     Socket new domain:#AF_INET type:#stream
     Socket new domain:#AF_UNIX type:#stream

specials
o  linger: anIntegerOrNil
set the linger behavior on close:
anIntegerOrNil == nil: close returns immediately, socket tries
to send buffered data in background.
anIntegerOrNil == 0: close returns immediately, bufferd data is discarded.
anIntegerOrNil > 0: close waits this many seconds for buffered data
to be delivered, after this time buffered data is
discarded and close returns with an error.
(returns false, if unsupported)

o  receiveBufferSize
get the send buffer size - for special applications only.
Not all operatingSystems offer this functionality
(returns nil, if unsupported)

o  receiveBufferSize: size
set the receive buffer size - for special applications only.
Not all operatingSystems offer this functionality
(returns false, if unsupported)

o  receiveTimeout
get the receive timeout in millis - for special applications only.
Not all operatingSystems offer this functionality
(returns nil, if unsupported)

usage example(s):

	Socket newTCP receiveTimeout

o  receiveTimeout: secondsOrTimeDuration
set the receive timeout - for special applications only.
Not all operatingSystems offer this functionality
(returns false, if unsupported).

From linux manpage:
SO_RCVTIMEO and SO_SNDTIMEO
Specify the receiving or sending timeouts until reporting an error. The argument is a
struct timeval. If an input or output function blocks for this period of time, and data has
been sent or received, the return value of that function will be the amount of data trans-
ferred; if no data has been transferred and the timeout has been reached, then -1 is
returned with errno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just as if
the socket was specified to be nonblocking. If the timeout is set to zero (the default),
then the operation will never timeout. Timeouts only have effect for system calls that per-
form socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect
for select(2), poll(2), epoll_wait(2), and so on.

usage example(s):

	Socket newTCP
	    receiveTimeout:5s;
	    receiveTimeout

o  sendBufferSize
get the send buffer size - for special applications only.
Not all operatingSystems offer this functionality
(returns nil, if unsupported)

o  sendBufferSize: size
set the send buffer size - for special applications only.
Not all operatingSystems offer this functionality
(returns false, if unsupported)

o  sendTimeout
get the send timeout in millis - for special applications only.
Not all operatingSystems offer this functionality
(returns nil, if unsupported)

usage example(s):

	Socket newTCP sendTimeout

o  sendTimeout: secondsOrTimeDuration
set the send timeout - for special applications only.
Not all operatingSystems offer this functionality
(returns false, if unsupported).
From linux manpage:
SO_RCVTIMEO and SO_SNDTIMEO
Specify the receiving or sending timeouts until reporting an error. The argument is a
struct timeval. If an input or output function blocks for this period of time, and data has
been sent or received, the return value of that function will be the amount of data trans-
ferred; if no data has been transferred and the timeout has been reached, then -1 is
returned with errno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just as if
the socket was specified to be nonblocking. If the timeout is set to zero (the default),
then the operation will never timeout. Timeouts only have effect for system calls that per-
form socket I/O (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect
for select(2), poll(2), epoll_wait(2), and so on.

usage example(s):

	Socket newTCP
	    sendTimeout:5s;
	    sendTimeout

o  setTCPCork: aBoolean
enable/disable TCP_CORK (do-not-send-partial-frames)
For special applications only.
Not all OperatingSystems offer this functionality
(returns false, if unsupported)

o  setTCPNoDelay: aBoolean
enable/disable TCP_NODELAY (i.e. disable/enable the Nagle algorithm)
For special applications only.
Not all OperatingSystems offer this functionality
(returns false, if unsupported)

waiting
o  waitForNewConnectionOrDataOnAny: otherConnections timeout: secondsOrTimeDurationOrNil
suspend the current process, until either a new connection comes
in at the receiver, or data arrives on any of the otherConnections.
For a new connection, an accept is performed and the new socket is returned.
For an old connection, that socket is returned.
In any case, the caller gets a socket to operate on as return value,
or nil, if a timeout occurred.
This method implements the inner wait-primitive of a multi-connection
server application.

o  waitForNewConnectionWithTimeout: secondsOrTimeDurationOrNil
suspend the current process, until a new connection comes
in at the receiver or a timeout occurs.
For a new connection, an accept is performed and the new socket is returned.
Returns nil, if a timeout occurred.
This method implements the inner wait-primitive of a single-connection
server application.


Examples:


example (get help info from an nntp server):
    |sock|

    sock := Socket newTCPclientToHost:'smtp.exept.de' port:'smtp'.
    sock isNil ifTrue:[
        self warn:'no smtp daemon is running'.
        ^ self
    ].
    Transcript showCR:sock nextLine.

    sock nextPutAll:'HELO STX socket test'; cr.
    Transcript showCR:sock nextLine.
    sock close
example (connect to finger daemon, get users entry):
    |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
    ]
example (connect to an ftp server):
    |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:'HELP'; cr.
    [
        |line|
        line := sock nextLine.
        Transcript showCR:line.
        (line at:4) = $-
    ] whileTrue.
    sock close.

    'don't know enough of the ftp protocol to continue here ...'
example (connect to an snmp server [UDP]): Note: this is not a real connection, only the destination address is being fixed.
    |sock port|

    sock := Socket newUDP.
    port := Socket portOfService:'snmp'.
    sock connectTo:'224.1.2.3' port:port.
    sock buffered:false.
    Transcript showCR:'got it'.
    sock close.
example (await connection from a client and read some data):
    |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.
        ]
    ]
example (connect to above server and send some data):
    |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
    ]
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. ] ] 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
    |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
    ]
example (UDP await packet from a client and read some data):
    |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
    ]
example (connect to above UDP server and send some data;
    |sock|

    sock := Socket newUDP.
    sock isNil ifTrue:[
        Transcript showCR:'nope'
    ] ifFalse:[
        sock
            sendTo:(IPSocketAddress hostName:'127.0.0.1' port:9999) buffer:'hello world'.
        sock close
    ]
example (UDP await packet from a client and read some multicast data):
    |udpSock sock addr n dataBuffer|

    udpSock := Socket newUDPserverAtPort:9999.
    udpSock isNil ifTrue:[
        Transcript showCR:'socket setup failed.'.
    ] ifFalse:[
        udpSock setSocketOption:#'IP_ADD_MEMBERSHIP' argument:#[224 1 2 3] argument:#[0 0 0 0].
        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
    ]
example (connect to above UDP server and send some multicast data):
    |sock|

    sock := Socket newUDP.
    sock isNil ifTrue:[
        Transcript showCR:'nope'
    ] ifFalse:[
        sock
            setSocketOption:#'IP_MULTICAST_TTL' argument:3 argument:nil;
            sendTo:(IPSocketAddress hostName:'224.1.2.3' port:9999) buffer:'hello world'.
        sock close
    ]
example: pingWalk (try to ping hosts on the local network) Note: it dosen't use ICMP ping, but tries to reache the echo service, which is disabled on most OS.
    |myAddress list top hosts walkProcess port|

    myAddress := OperatingSystem getNetworkAddresses
                    keysAndValuesSelect:[:eachIFName :eachAddress|
                        eachAddress isLocal not
                        and:[eachIFName = 'wlan0']
                    ].
    myAddress := myAddress first hostAddress.

    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'.
This example creates a simple UDP server that accepts single packets from anybody and broadcasts them to all clients that have connected so far.
    | 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
    ]
send a datagram to above server:

    | 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
loopBack:

    |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.


ST/X 7.2.0.0; WebServer 1.670 at bd0aa1f87cdd.unknown:8081; Fri, 19 Apr 2024 23:57:32 GMT