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.440 date: 2024/02/19 14:13:49
user: cg
file: Socket.st directory: libbasic2
module: stx stc-classLibrary: libbasic2

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.

copyright

COPYRIGHT (c) 1992 by Claus Gittinger All Rights Reserved This software is furnished under a license and may be used only in accordance with the terms of that license and with the inclusion of the above copyright notice. This software may not be provided or otherwise made available to, or used by, any other person. No title to or ownership of the software is hereby transferred.

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: numSeconds
return a timestamp numSeconds from now

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 without notice in later versions

Usage example(s):

     Socket debug:true
     Socket debug:false

o  defaultConnectTimeout

o  defaultConnectTimeout: secondsOrTimeDuration

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

o  defaultIpDomainOrderForConnect
answer the order of inet domains when trying to connect:
#AF_INET IPv4
#AF_INET6 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  newTCP
marked as obsolete by Stefan Vogel at 17-Aug-2022

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

o  newTCP: portNrOrServiceName
create a IPv4 TCP socket for a service -
neither connect nor connect-wait is done.
OBSOLETE, since not compatible with IPv6!

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

o  newTCP: portNrOrServiceName useIPv6: useIPv6
create a TCP socket for a service -
neither connect nor connect-wait is done.
If portNrOrServiceName is non-nil, bind to the port.
If portNrOrServiceName is 0, bind to an unused port allocated by the OS.
If portNrOrServiceName is nil, do not bind.

Usage example(s):

	Socket newTCP:'http-alt'.
	Socket newTCP:9996 useIPv6:false.
	Socket newTCP:9996 useIPv6:true.

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 domainOrder: orderOrNil withTimeout: milliSecondsOrTimeDuration
create a new TCP client socket connecting to a service on hostNameOrAddress.
If hostNameOrAddress is a string, try all the resolved addresses.
Set aDomainSymbolOrNil to #AF_INET of #AF_INET6 to connect via a defined protocol.
Set aDomainSymbolOrNil to nil, to try all protocols.
orderOrNil may be a list of domain symbols or nil.
if not nil, the attempts to establish a connection fo the different domains is
done in this order.
If the milliSecondsOrTimeDuration arg is nonNil,
stop trying to connect after that many milliSecondsOrTimeDuration
and return nil.
Return a socket instance if ok.
On failure raise a SocketErrorNotification (which is ignored if not handled)
and return nil.

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.
On failure raise a SocketErrorNotification (which is ignored if not handled)
and return nil.
Set aDomainSymbolOrNil to #AF_INET of #AF_INET6 to connect via a defined protocol.
Set aDomainSymbolOrNil to nil, to try all protocols as defined in #defaultIpDomainOrderForConnect.
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.
Try all protocols as defined in #defaultIpDomainOrderForConnect.
Return a socket instance if ok.
On failure raise a SocketErrorNotification (which is ignored if not handled)
and return nil.
If the millis arg is nonNil, stop trying to connect after that many milliseconds
and return nil.

o  newTCPserverAtAddress: anIPSocketAddress backlog: backLogCount
create a new TCP server socket providing service.
backLogCount is the max number of un-accepted connect requests, that will be queued.
If anIPSocketAddress is an IPv6SocketAddress the connection will both handle both IPv6 and IPv4 connections.
If anIPSocketAddress is an IPSocketAddress (i.e. IPv4) the connection will only handle IPv4 connections.
If the address part of anIPSocketAddress is anyHost (or not set), connections on any interface will be accepted.
If the address part of anIPSocketAddress is a specific IP address, connections only on the interface with this address will be accepted.
If the port of anIPSocketAddress is 0, a unused port will be assigned.

Usage example(s):

      An IPv4 Socket on port 5678:
	self newTCPserverAtAddress:(IPSocketAddress anyHost port:5678) backlog:1

      An IPv4 Socket with an unused port assigned by the OS:
	self newTCPserverAtAddress:IPSocketAddress anyHost backlog:1

      An IPv6 Socket (also accepting IPv4 connections) with an unused port assigned by the OS:
	self newTCPserverAtAddress:IPv6SocketAddress anyHost backlog:1

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
marked as obsolete by Stefan Vogel at 17-Aug-2022

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

o  newUDP: aServiceOrNil
create an IPv4 UDP socket for a service -
neither connect nor connect-wait is done.
aServiceOrNil may be the port number or the name of a service.

OBSOLETE, since not compatible with IPv6!

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

o  newUDP: portNrOrServiceName useIPv6: useIPv6
create a UDP socket for a service -
neither connect nor connect-wait is done.
aServiceOrNil may be the port number or the name of a service

Usage example(s):

	Socket newUDP:4444 useIPv6:true.
	Socket newUDP:4444 useIPv6:false.
	Socket newUDP:'activesync' useIPv6:true.
	Socket newUDP:0 useIPv6:true.

o  newUDPclientToAddress: aSocketAddress
create a new UDP client socket connecting to a service
(i.e. set the default address where all packets are sent to).
Return a socket instance if ok, nil on failure.

Usage example(s):

	self newUDPclientToAddress:IPSocketAddress localHost.
	self newUDPclientToAddress:IPv6SocketAddress localHost.

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.

Usage example(s):

     |s s2|

    '/tmp/foo' asFilename remove.
     s := Socket newUNIXserverAt:'/tmp/foo'.
     s listenFor:5.
     s2 := s accept.

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,
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 of 16 bytes,
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  nameAndProtocolOfService: aNameOrNumber
returns the service name (as string) and protocol for a given port nr
or nil if no such service exists.

Usage example(s):

     Socket nameAndProtocolOfService:79    => #('finger' 'tcp')
     Socket nameAndProtocolOfService:80    => #('http' 'tcp')
     Socket nameAndProtocolOfService:8080  => #('http-alt' 'tcp')
     Socket nameAndProtocolOfService:3306  => #('mysql' 'tcp')
     Socket nameAndProtocolOfService:33060 => #('mysqlx' 'tcp')
     Socket nameAndProtocolOfService:1900  => #('ssdp' 'tcp')

o  nameOfService: aNameOrNumber
returns the service name (as string) for a given port nr
or nil if no such service exists.

Usage example(s):

     Socket nameOfService:79
     Socket nameOfService:80
     Socket nameOfService:8080

o  namesAndProtocolsOfService: aNameOrNumber
returns a collection of service names (as string), service protocol (string)
and service port,
given a port nr or service name
or an empty collection if no such service exists.
Returns something like #(#('ping' 'udp' portNr) ('ping' 'tcp' portNr)))

Usage example(s):

     Socket namesAndProtocolsOfService:79
     Socket namesAndProtocolsOfService:80
     Socket namesAndProtocolsOfService:8080
     Socket namesAndProtocolsOfService:33060
     Socket namesAndProtocolsOfService:1900

o  peerFromDomain: domain name: peerName port: port
marked as obsolete by Stefan Vogel at 1-Feb-2024

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

o  peerNameFromDomain: domain peer: peer
marked as obsolete by Stefan Vogel at 1-Feb-2024

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

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'
     Socket portOfService:'ssdp'

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'
     Socket portOfService:'ssdp' protocol:'udp'
     Socket portOfService:'ssdp' 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'
     Socket protocolOfService:'ssdp'
     Socket nameAndProtocolOfService:'ssdp'
     Socket nameAndProtocolOfService:1900

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')

o  wellknownNameAndProtocolOfService: aNumber
returns the service name (as string) and protocol for a given port nr
or nil if unknown.
This is a fallback, for some heuristic wellknown services
(for which getservbyport does not return anything useful)


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  localPort

o  noTimeout
disable timeouts - dummy for now

o  peerName
return my peer as SocketAddress (i.e. ipAddr + port)
(bad naming: not as string) ;
May return nil if not yet setup completely.

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

o  receiveDataInto: aDataBuffer
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  receiveUDPDataInto: aDataBuffer
( an extension from the stx:libcompat package )
in squeak, an UDP-receive into aDataBuffer returns a 4-element vector consisting of:
number of bytes
host address of sender
portnr of sender
true/false if error

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  waitForAcceptFor: secondsToWait
timed out

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: ifClosedBlock
( an extension from the stx:libcompat package )
wait for incoming data;
if the socket gets closed, evaluate aBlock

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

Usage example(s):

     |sock newSock|

     sock := Socket provide:8004.
     sock listenFor:5.
     newSock := sock accept.

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  listen
start listening; return true if ok, false on error.
Notify with a SocketErrorNotification on error.
One outstanding connect request may be queued on the socket
(i.e. this is the same as listenFor:1)

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

o  shutDownInput
shutDown the input side of the socket.
After already received data that hat been buffered in the OS,
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.
Callers should be changed to call connectTo:aSocketAddress withTimeout:
(i.e. pass 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 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  setKeepAlive: aBoolean
set/clear the SO_KEEPALIVE socket option

o  setSocketOption: option argument: arg1 argument: arg2
option is a symbol:
#IP_DROP_MEMBERSHIP <addr-bytes> <addr-bytes>
#IP_ADD_MEMBERSHIP <addr-bytes> <addr-bytes>
#IP_TTL <int>
#IP_MULTICAST_TTL <int>
#IPV6_V6ONLY <bool>
#SO_BROADCAST <bool>
#SO_CONDITIONAL <bool>
#SO_DEBUG <bool>
#SO_DONTLINGER <bool>
#SO_LINGER <bool> <nil | int>
#SO_DONTROUTE <bool>
#SO_KEEPALIVE <bool>
#SO_OOBINLINE <bool>
#SO_RCVBUF <int>
#SO_SNDBUF <int>
#SO_REUSEADDR <bool>
#SO_REUSEPORT <bool>
#SO_EXCLUSIVEADDRUSE <bool>
#SO_RCVTIMEO <seconds-int> <uSec-int>
#SO_SNDTIMEO <seconds-int> <uSec-int>
#TCP_NODELAY <bool>
arg is option specific
#OPTION { <level-int> <option-int> } <rawData>
to generate an arbitrary socket opton call, in case it is as-yet unimplemented
Must generate a matching byteArray as rawData
and pass both level and option as 2-element array in first arg

o  shutdown: howNum
shutDown the socket - inform it that no more I/O will be performed.
0 - read side (no further reads)
Stop receiving data for this socket. If further data arrives, reject it
(the tcp receive window is closed, so the peer cannot send more data).
Data that has already been received and buffered in the OS can still be read.

1 - write side (no further writes - subsequent writes will fail)
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.
The connection is terminated, but the file descriptor still needs to be closed.

printing & storing
o  name
for monitoring (see ExternalStreamMonitor)

o  name: aString
for monitoring (see ExternalStreamMonitor)

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  canAcceptWithoutBlocking
return true, if an incoming connections is pending (i.e.
an accept operation will not block the smalltalk process), false otherwise.
We know, that error conditions do not block, so return true for errors.

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

o  getFullPeerAddress
Answer the peer socket address; that is the socket address of the
partner's host after an connect or accept.

o  getFullSocketAddress
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
partner's host after an accept.

o  getSocketAddress
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  isListening

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's domain

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)

support websocket
o  blockingNextPutAllForNonBlockingSocket: someBytes
explanation of the method name:
blocking -> this method blocks its STX process until all bytes have been written
ForNonBlockingSocket -> this method only works with non-blocking sockets

the write is done within the current thread,
but the primitiv #send returns because the socket is non-blocking (in case of would block).
of cause if you write big data at once and the socket never would block, STX will freeze,
so please split big data into small packages

o  setNonBlocking
DO NOT move this functionality into Win32OperatingSystem #setBlocking:fd:,
because it will not work correctly, caused by the following problems.
and even if the problems has been fixed, it would change the behavior for all sockets (not only websockets)

o  systemBlockingNextPutAll: bytes
explanation of the method name:
systemBlocking -> this method blocks the entire STX
until all bytes have been written or until the socket would block

so please split big data into small packages

testing
o  isSSLSocket

waiting
o  waitForConnectOrAccept: secondsOrTimeDurationOrNil
wait for the connection secondsOrTimeDurationOrNil.
Return true when connect finished or an incoming connection is
pending for accept.
Return false on timeout.

o  waitForConnection: secondsOrTimeDurationOrNil
wait for the connection secondsOrTimeDurationOrNil.
Return true if connected

o  waitForConnectionUntil: deadlineTimestamp
Wait up until the given deadline for a connection to be established.
Return true if it is established by the deadline, false if not.

o  waitForConnectionWithErrorOnTimeout: secondsOrTimeDurationOrNil
wait for the connection secondsOrTimeDurationOrNil.
Raise an error if not connected.

o  waitForNewConnectionOrDataOnAny: otherConnections timeout: secondsOrTimeDurationOrNil
suspend the current process, until either a new connection comes
in at the receiver (a listening socket), 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 listening 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 - here SSDP data):
    |udpSock sock addr n dataBuffer|

    udpSock := Socket newUDPserverAtPort:1900.
    udpSock isNil ifTrue:[
        Transcript showCR:'socket setup failed.'.
    ] ifFalse:[
        (udpSock setSocketOption:#'IP_ADD_MEMBERSHIP' argument:#[239 255 255 250] argument:#[0 0 0 0]) ifFalse:[
            Transcript showCR:'IP_ADD_MEMBERSHIP0 failed.'.
        ].
        (udpSock setSocketOption:#'IP_ADD_MEMBERSHIP' argument:#[239 255 255 250] argument:#[127 0 0 1]) ifFalse:[
            Transcript showCR:'IP_ADD_MEMBERSHIP1 failed.'.
        ].
        (udpSock setSocketOption:#'IP_ADD_MEMBERSHIP' argument:#[239 255 255 250] argument:#[172 23 1 62]) ifFalse:[
            Transcript showCR:'IP_ADD_MEMBERSHIP2 failed.'.
        ].
        [
            [
                Transcript showCR:'wait'.
                udpSock readWait.

                addr := IPv6SocketAddress 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 asIPv4SocketAddressIfPossible printString).
                    Transcript showCR:('data: ' , (dataBuffer copyTo:n) printString).
                ] ifFalse:[
                    Transcript showCR:'read failed'.
                ].
            ] loop.
        ] ensure:[
            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:4 argument:nil.
        [
            [
                sock sendTo:(IPSocketAddress hostName:'239.255.255.250' port:1900) buffer:'Invalid SSDP data for test'.
                Delay waitForSeconds:2.
            ] loop.
        ] ensure:[
            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 openAndWaitUntilVisible.

    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.
This example creates a simple UDP server that accepts single NTP packets and prints the time on the Transcript.
    | socket address buffer msgSize msg |

    address := IPSocketAddress new.
    buffer := ByteArray new: 1024.

    socket := self newUDPserverAtPort:123.

    Transcript showCR: 'ntp receiver starting'.

    [
        [true] whileTrue: [
            (socket readWaitWithTimeoutMs:1000) ifFalse:[
                msgSize := socket
                        receiveFrom: address
                        buffer: buffer
                        start: 1
                        for: buffer size.
                Transcript showCR: e'got {msgSize} bytes'.
                msg := buffer copyTo:msgSize.
            ]
        ]
    ] ensure:[
        Transcript showCR: 'server shutting down'.
        socket close
    ]


ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Sat, 21 Dec 2024 16:34:09 GMT