SocketAddress.st
author Claus Gittinger <cg@exept.de>
Wed, 21 May 2003 23:22:17 +0200
changeset 1232 49ce4681f1c0
parent 1229 b96b65284981
child 1259 0a557e59ea4a
permissions -rw-r--r--
dont wine if we get multiple host addresses for a name

"
 COPYRIGHT (c) 1995 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.
"

"{ Package: 'stx:libbasic2' }"

UninterpretedBytes variableByteSubclass:#SocketAddress
	instanceVariableNames:''
	classVariableNames:'DomainToClassMapping'
	poolDictionaries:''
	category:'OS-Sockets'
!

!SocketAddress class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1995 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.
"
!

documentation
"
    Abstract superclass for subclasses implementing various IPC addressing schemes.
    See concrete examples IPSocketAddress and UDSocketAddress.

    ST-80 compatibility class.
    This may be required when existing code has to be ported to ST/X;
    however, it may not be complete and more protocol may be added in the future.
    The code here was created when public domain code (Manchester) had to
    be ported to ST/X and missing classes/methods were encountered, and code added
    by reasoning 'what the original class could probably do there'.

    This is an additional goody class; therefore:

    THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTOR ``AS IS'' AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTOR BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    SUCH DAMAGE.
"
! !

!SocketAddress class methodsFor:'instance creation'!

hostAddress:addr
    "get a new instance given addr-bytes"

    ^ self hostAddress:addr port:0
!

hostAddress:addr port:portNr
    "get a new instance given addr-bytes and a portNr"

    ^ self new hostAddress:addr; port:portNr
!

hostName:name
    "get a new instance given a hostname"

    ^ self hostName:name serviceName:nil type:nil
!

hostName:name port:portNr
    "get a new instance given a hostname and port"

    ^ self hostName:name serviceName:portNr type:nil
!

hostName:name serviceName:portNrOrName type:socketTypeSymbol
    "get a new instance given a hostname, port or service and type"

    |addressInfo serviceName port sa|

    portNrOrName isString ifTrue:[
        serviceName := portNrOrName
    ] ifFalse:[
        port := portNrOrName.
    ].

    addressInfo := self 
                    getAddressInfo:name 
                    serviceName:serviceName 
                    domain:(self domainSymbol) 
                    type:socketTypeSymbol
                    protocol:nil 
                    flags:0.

    sa := addressInfo first socketAddress.
    addressInfo size > 1 ifTrue:[
        (addressInfo contains:[:entry| entry socketAddress ~= sa]) ifTrue:[
            'SocketAddress [warning]: multiple hostAddresses for host' infoPrintCR.
        ].
    ].
    port notNil ifTrue:[
        sa port:port.
    ].
    ^ sa

    "
     SocketAddress hostName:'localhost' serviceName:10 type:#stream
     IPSocketAddress hostName:'localhost' serviceName:'echo' type:#datagram 
     IPSocketAddress hostName:'localhost' serviceName:'echo' type:nil
    "
!

new
    |numBytes|

    self == SocketAddress ifTrue:[
        self error:'SocketAddress is abstract'.
    ].

    numBytes := self socketAddressSize.
    numBytes isNil ifTrue:[
        self error:'unsupported domain'.
        ^ nil
    ].
    ^ (self new:numBytes) domainCode:(self domainCode)

    "
     IPSocketAddress new            
     IPv6SocketAddress new          
     UDSocketAddress new            
     AppletalkSocketAddress new
   "
!

newDomain:domain
   "answer an new socket address for a given domain"

   ^ (self knownClassFromCode:domain) new

   "
    self newDomain:#afUnix    
    self newDomain:#afInet    

    self newDomain:#'AF_UNIX' 
    self newDomain:#'AF_INET' 

    self newDomain:#unix
    self newDomain:#inet
   "
! !

!SocketAddress class methodsFor:'queries'!

domainCode
    "answer the numerical domain code used in socket addresses"

    ^ OperatingSystem socketAccessor domainCodeOf:self domainSymbol
!

domainCodeFromName:aNameSymbol
    "this is a compatibility method;
     VW returns the internal unix codes here - however, in ST/X,
     symbols are returned, which are translated later"

    aNameSymbol == #afUnix      ifTrue:[^ #'AF_UNIX'].
    aNameSymbol == #afInet      ifTrue:[^ #'AF_INET'].    
    aNameSymbol == #afIpV6      ifTrue:[^ #'AF_INET6'].    
    aNameSymbol == #afAppletalk ifTrue:[^ #'AF_APPLETALK'].    
    aNameSymbol == #afDecnet    ifTrue:[^ #'AF_DECnet'].    
    aNameSymbol == #afSna       ifTrue:[^ #'AF_SNA'].    
    aNameSymbol == #afNs        ifTrue:[^ #'AF_NS'].    
    aNameSymbol == #afCcitt     ifTrue:[^ #'AF_CCITT'].    
    aNameSymbol == #afImplink   ifTrue:[^ #'AF_IMPLINK'].    
    aNameSymbol == #afPup       ifTrue:[^ #'AF_PUP'].    
    aNameSymbol == #afChaos     ifTrue:[^ #'AF_CHAOS'].    
    aNameSymbol == #afEcma      ifTrue:[^ #'AF_ECMA'].    
    aNameSymbol == #afDatakit   ifTrue:[^ #'AF_DATAKIT'].    
    aNameSymbol == #afDli       ifTrue:[^ #'AF_DLI'].    
    aNameSymbol == #afLat       ifTrue:[^ #'AF_LAT'].    
    aNameSymbol == #afHylink    ifTrue:[^ #'AF_HYLINK'].    

    aNameSymbol == #afUnspec    ifTrue:[^ #'AF_UNSPEC'].    

    "/
    "/ could someone tell me which symbols are used in ST-80's SocketAddress class ?
    "/
    self error:'no more mimicri implemented yet ...'

    "Modified: / 9.1.1998 / 10:03:56 / stefan"
!

domainNameFromCode:code
    "this is a compatibility method;
     VW expects the internal unix codes here - however, in ST/X,
     symbols are expected - keeping the numeric values secret (in Socket)"

    code == #unix           ifTrue:[^ #afUnix].
    code == #'AF_UNIX'      ifTrue:[^ #afUnix].
    code == #inet           ifTrue:[^ #afInet].
    code == #'AF_INET'      ifTrue:[^ #afInet].
    code == #inet6          ifTrue:[^ #afIpV6].
    code == #'AF_INET6'     ifTrue:[^ #afIpV6].
    code == #appletalk      ifTrue:[^ #afAppletalk].
    code == #'AF_APPLETALK' ifTrue:[^ #afAppletalk].
    code == #DECnet         ifTrue:[^ #afDecnet].
    code == #'AF_DECNET'    ifTrue:[^ #afDecnet].
    code == #sna            ifTrue:[^ #afSna].
    code == #'AF_SNA'       ifTrue:[^ #afSna].
    code == #xns            ifTrue:[^ #afNs].
    code == #'AF_NS'        ifTrue:[^ #afNs].
    code == #ccitt          ifTrue:[^ #afCcitt].
    code == #'AF_CCITT'     ifTrue:[^ #afCcitt].

    "/
    "/ could someone tell me which symbols are used in ST-80's SocketAddress class ?
    "/
    self error:'no more mimicri implemented yet ...'
!

domainSymbol
    "answer the domain symbol. Subclasses redefine this"

    self == SocketAddress ifTrue:[
        ^ nil
    ] ifFalse:[
        self subclassResponsibility
    ]
!

getAddressInfo:hostName serviceName:serviceName domain:domainArg type:typeArg protocol:protoArg flags:flags 
    "answer an Array of socket addresses for serviceName on hostName
     Domain, type, protocol may be nil or specify a hint for the socket 
     addresses to be returned."

    ^ OperatingSystem socketAccessor 
            getAddressInfo:hostName serviceName:serviceName 
            domain:domainArg type:typeArg protocol:protoArg flags:flags 

    "
     self getAddressInfo:'localhost' serviceName:nil 
            domain:nil type:nil protocol:nil flags:nil
     self getAddressInfo:'localhost' serviceName:nil 
            domain:#inet type:#stream protocol:nil flags:nil
     self getAddressInfo:'localhost' serviceName:nil 
            domain:#inet type:#stream protocol:#tcp flags:nil
     self getAddressInfo:'blurb.exept.de' serviceName:nil 
            domain:#inet type:nil protocol:nil flags:nil
     self getAddressInfo:'1.2.3.4' serviceName:'6' 
            domain:#inet type:nil protocol:nil flags:nil
     self getAddressInfo:'localhost' serviceName:'echo' 
            domain:#inet6 type:nil protocol:nil flags:nil
    "
!

getAddressInfo:hostName serviceName:serviceName type:typeArg protocol:protoArg flags:flags 
    "answer an Array of socket addresses for serviceName on hostName
     Domain, type, protocol may be nil or specify a hint for the socket 
     addresses to be returned."

    ^ self  
        getAddressInfo:hostName serviceName:serviceName 
        domain:(self domainCode) type:typeArg protocol:protoArg flags:flags 

    "
     IPSocketAddress getAddressInfo:'localhost' serviceName:nil 
                     type:nil protocol:nil flags:nil
     IPSocketAddress getAddressInfo:'localhost' serviceName:nil 
                     type:#stream protocol:nil flags:nil
     IPSocketAddress getAddressInfo:'localhost' serviceName:nil 
                     type:#stream protocol:#tcp flags:nil
     IPSocketAddress getAddressInfo:'blurb.exept.de' serviceName:nil 
                     type:nil protocol:nil flags:nil
     IPSocketAddress getAddressInfo:'1.2.3.4' serviceName:'6' 
                     type:nil protocol:nil flags:nil
     IPSocketAddress getAddressInfo:'localhost' serviceName:'echo' 
                     type:nil protocol:nil flags:nil
    "
!

getNameInfo:socketAddress wantHostName:wantHostName wantServiceName:wantServiceName datagram:useDatagram flags:flags 
    "answer an Array containing the hostName and serviceName
     in socketAddress. SocketType may be one "

    ^ OperatingSystem socketAccessor
            getNameInfo:socketAddress wantHostName:wantHostName 
            wantServiceName:wantServiceName datagram:useDatagram flags:flags 
    
    "
     self getNameInfo:
         (self getAddressInfo:'localhost' serviceName:'echo' 
                domain:#inet type:#stream protocol:nil flags:nil) first socketAddress
         wantHostName:true wantServiceName:true datagram:false flags:0
    "
!

knownClassFromCode:code
    "this is a compatibility method;
     VW expects the internal unix codes here - however, in ST/X,
     symbols are expected - keeping the numeric values secret (in Socket)"

    |cls|

    DomainToClassMapping isNil ifTrue:[
        DomainToClassMapping := IdentityDictionary new
    ].
    cls := DomainToClassMapping at:code ifAbsent:nil.
    cls notNil ifTrue:[^ cls].
    code notNil ifTrue:[
        self allSubclassesDo:[:aSubClass|
            (aSubClass domainCode == code
            or:[aSubClass domainSymbol == code
            or:[aSubClass obsoleteDomainSymbol == code
            or:[aSubClass vwDomainSymbol == code]]])
            ifTrue:[
                DomainToClassMapping at:code put:aSubClass.
                ^ aSubClass
            ].
        ].
    ].
    ^ SocketAddress

    "
     self knownClassFromCode:#'AF_UNIX' 
     self knownClassFromCode:#'AF_INET'

     self knownClassFromCode:1
     self knownClassFromCode:2

     self knownClassFromCode:#unix             obsolete ST/X codes
     self knownClassFromCode:#inet

     self knownClassFromCode:#afUnix           visualWorks codes
     self knownClassFromCode:#afInet
    "
!

obsoleteDomainSymbol
    ^ nil
!

socketAddressSize
    "answer the OS specific size of a socket address"

    ^ OperatingSystem socketAccessor socketAddressSize:(self domainSymbol)

    "
     UDSocketAddress socketAddressSize
     IPSocketAddress socketAddressSize  
     IPv6SocketAddress socketAddressSize
     AppletalkSocketAddress socketAddressSize  
     DecNetSocketAddress socketAddressSize     
    "
!

vwDomainSymbol
    ^ nil
! !

!SocketAddress methodsFor:'accessing'!

domainCode

    ^ self unsignedShortAt:1
!

domainCode:anInteger

    self unsignedShortAt:1 put:anInteger
!

hostAddress:addressBytes
    "generic method, subclasses usually redefine this"

    "/ the first 2-bytes (a short) is the domainCode
    self replaceBytesFrom:1+2 to:addressBytes size+2 with:addressBytes startingAt:1

    "
     IPSocketAddress hostAddress:#[193 141 12 193] port:80
    "
!

hostAddress:addressBytes port:portNr
    self hostAddress:addressBytes.
    self port:portNr

    "
     IPSocketAddress hostAddress:#[193 141 12 193] port:10
    "
!

port
    self subclassResponsibility
!

port:portNr
    self subclassResponsibility
! !

!SocketAddress methodsFor:'printing & storing'!

displayString
    "redefine from Collection"

    |s|

    s := WriteStream on:''.
    self printOn:s.
    ^ s contents.
! !

!SocketAddress methodsFor:'private'!

fromBytes:aByteArray
    "Copy the internal representation of a SocketAddress to myself

     This is an internal interface!!"

    self replaceBytesFrom:1 to:(self size) with:aByteArray startingAt:1.


! !

!SocketAddress methodsFor:'queries'!

address
    ^ self subclassResponsibility
!

hostName
    ^ (self class getNameInfo:self wantHostName:true 
                  wantServiceName:false datagram:false flags:0) first

    "
     (IPSocketAddress hostAddress:#[127 0 0 1] port:7) hostName
     (IPSocketAddress hostAddress:#[193 141 12 193] port:10) hostName 
     (IPSocketAddress hostAddress:#[193 141 12 244]) hostName 
    "
!

portOrName
    ^ self subclassResponsibility
!

serviceName
    ^ (self class getNameInfo:self wantHostName:false 
                  wantServiceName:true datagram:false flags:0) second

    "
     (IPSocketAddress hostAddress:#[127 0 0 1] port:7) serviceName
     (IPSocketAddress hostAddress:#[193 141 12 193] port:10) serviceName
    "
! !

!SocketAddress class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic2/SocketAddress.st,v 1.17 2003-05-21 21:22:17 cg Exp $'
! !