New socket support
authorStefan Vogel <sv@exept.de>
Thu, 27 Mar 2003 14:30:01 +0100
changeset 1164 41a2750af1fa
parent 1163 bf124794e128
child 1165 41276f24118f
New socket support
IPSocketAddress.st
SocketAddress.st
UDSocketAddress.st
--- a/IPSocketAddress.st	Thu Mar 27 14:29:58 2003 +0100
+++ b/IPSocketAddress.st	Thu Mar 27 14:30:01 2003 +0100
@@ -1,6 +1,6 @@
 "
  COPYRIGHT (c) 1995 by Claus Gittinger
-              All Rights Reserved
+	      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
@@ -13,7 +13,7 @@
 "{ Package: 'stx:libbasic2' }"
 
 SocketAddress variableByteSubclass:#IPSocketAddress
-	instanceVariableNames:'port'
+	instanceVariableNames:''
 	classVariableNames:''
 	poolDictionaries:''
 	category:'OS-Sockets'
@@ -24,7 +24,7 @@
 copyright
 "
  COPYRIGHT (c) 1995 by Claus Gittinger
-              All Rights Reserved
+	      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
@@ -65,70 +65,97 @@
 
 !IPSocketAddress class methodsFor:'instance creation'!
 
-new
-    ^ self new:4
+hostAddress:addressBytes port:portNumber
 
-
+    ^ self new hostAddress:addressBytes; port:portNumber
 ! !
 
-!IPSocketAddress class methodsFor:'queries'!
+!IPSocketAddress class methodsFor:'addressing'!
+
+anyAddress
+    "return the broadcast address"
+
+    ^ #[255 255 255 255]
+!
+
+anyPort
+    "return the anon port number"
+
+    ^ 0
+!
 
 bytesToName:addrBytes
     ^ Socket hostWithIpAddress:addrBytes
 !
 
+firstUnreservedPort
+    "return the first unreserved port number"
+
+    ^ 1024
+!
+
 hostAddressByName: hostName
     ^ Socket ipAddressOfHost:hostName
+!
 
-    "
-     IPSocketAddress hostAddressByName:'clam' 
-     IPSocketAddress hostAddressByName:'foobar' 
-    "
+local
+    "return IN_ADDR_ANY, the address matching any local address"
+
+    ^ #[127 0 0 1]
 !
 
-hostNameByAddress: anAddress
-    ^ Socket hostWithIpAddress:anAddress
+maxPort
+    "return the maximum port number"
 
-    "
-     |addr|
-
-     addr := IPSocketAddress hostAddressByName:'porty'.
-     IPSocketAddress hostNameByAddress:addr  
-    "
+    ^ 16rffff
 !
 
-servicePortByName:serviceName
-    ^ Socket portOfService:serviceName
+thisHost
+    "return IN_ADDR_ANY, the address matching any local address"
+
+    ^ #[0 0 0 0]
+! !
+
+!IPSocketAddress class methodsFor:'queries'!
 
-    "
-     IPSocketAddress servicePortByName:'nntp' 
-     IPSocketAddress servicePortByName:'time' 
-    "
+domainSymbol
+
+    ^ #inet
+!
+
+socketAddressSize
+    "This is OS dependent"
+    
+    ^ OperatingSystem socketAccessor socketAddressSize:#inet
 ! !
 
 !IPSocketAddress methodsFor:'accessing'!
 
 hostAddress
-    ^ (ByteArray new:4) replaceFrom:1 to:4 with:self startingAt:1
-
+    ^ (ByteArray new:4) replaceFrom:1 to:4 with:self startingAt:5
 !
 
-hostName:name port:portNr
-    self 
-        hostAddress:(Socket ipAddressOfHost:name)
-        port:portNr
-
-    "
-     IPSocketAddress hostName:'exept' port:10
-    "
+hostAddress:aByteArray
+    ^ self replaceFrom:5 to:8 with:aByteArray startingAt:1
 !
 
 port
-    ^ port
+    ^ self unsignedShortAt:3 bigEndian:true
 !
 
 port:aPortNr
-    port := aPortNr
+
+    self unsignedShortAt:3 put:aPortNr bigEndian:true
+! !
+
+!IPSocketAddress methodsFor:'obsolete'!
+
+address
+    ^ self hostAddress
+!
+
+portOrName
+    ^ self port
 ! !
 
 !IPSocketAddress methodsFor:'printing & storing'!
@@ -137,40 +164,22 @@
     "append a user printed representation of the receiver to aStream.
      The format is suitable for a human - not meant to be read back."
 
-    1 to:4 do:[:i | 
-        (i between:2 and:4) ifTrue:[
-            aStream nextPut:$.
-        ].
-        (self at:i) printOn:aStream
-    ].
-    port notNil ifTrue:[
-        aStream nextPut:$:.
-        port printOn:aStream.
-    ].
-! !
-
-!IPSocketAddress methodsFor:'queries'!
+    |port|
 
-address
-    ^ self hostAddress
-!
-
-hostName
-    ^ Socket hostWithIpAddress:self
-
-    "
-     (IPSocketAddress hostAddress:#[193 141 12 193] port:10) hostName
-    "
-
-    "Created: 2.11.1995 / 11:17:28 / cg"
-!
-
-portOrName
-    ^ port
+    5 to:8 do:[:i | 
+	i ~~ 5 ifTrue:[
+	    aStream nextPut:$.
+	].
+	(self at:i) printOn:aStream
+    ].
+    (port := self port) ~~ 0 ifTrue:[
+	aStream nextPut:$:.
+	port printOn:aStream.
+    ].
 ! !
 
 !IPSocketAddress class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic2/IPSocketAddress.st,v 1.14 2002-03-08 16:30:47 penk Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/IPSocketAddress.st,v 1.15 2003-03-27 13:29:29 stefan Exp $'
 ! !
--- a/SocketAddress.st	Thu Mar 27 14:29:58 2003 +0100
+++ b/SocketAddress.st	Thu Mar 27 14:30:01 2003 +0100
@@ -10,6 +10,8 @@
  hereby transferred.
 "
 
+"{ Package: 'stx:libbasic2' }"
+
 UninterpretedBytes variableByteSubclass:#SocketAddress
 	instanceVariableNames:''
 	classVariableNames:''
@@ -67,17 +69,76 @@
     ^ self new hostAddress:addr port:portNr
 !
 
+hostName:name
+    ^ self hostName:name serviceName:nil type:nil
+!
+
 hostName:name port:portNr
-    ^ self new hostName:name port:portNr
+    ^ self hostName:name serviceName:portNr type:nil
+!
+
+hostName:name serviceName:portNrOrName type:socketTypeSymbol
+
+    |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:[
+            self error:'too many results'
+        ].
+    ].
+    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
-    ^ self subclassResponsibility
+    ^ (self new:self socketAddressSize) 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:#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,
@@ -121,34 +182,106 @@
 
 !
 
+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
+    "
+!
+
+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)"
 
-    code == #unix      ifTrue:[^ #UDSocketAddress].
-    code == #inet      ifTrue:[^ #IPSocketAddress].
-    code == #inet6     ifTrue:[^ #IPv6SocketAddress].
-    code == #appletalk ifTrue:[^ #AppletalkSocketAddress].
-    code == #DECnet    ifTrue:[^ #DECNetSocketAddress].
-    code == #sna       ifTrue:[^ #SNASocketAddress].
-    code == #xns       ifTrue:[^ #XNSSocketAddress].
-    code == #ccitt     ifTrue:[^ #CCITTSocketAddress].
+    code isInteger ifTrue:[
+        self allSubclassesDo:[:cls|
+            cls domainCode == code ifTrue:[
+                ^ cls
+            ].
+        ].
+    ] ifFalse:[
+        self allSubclassesDo:[:cls|
+            cls domainSymbol == code ifTrue:[
+                ^ cls
+            ].
+        ].
+    ].
+    ^ SocketAddress
 
-    "/
-    "/ could someone tell me which symbols are used in ST-80's SocketAddress class ?
-    "/
-    self error:'no more mimicri implemented yet ...'.
-    ^ #SocketAddress
+    "
+     self knownClassFromCode:#unix
+     self knownClassFromCode:#inet
+     self knownClassFromCode:2
+    "
+!
 
+socketAddressSize
+    "answer the OS specific size of a socket address"
+
+    ^ self subclassResponsibility
 ! !
 
 !SocketAddress methodsFor:'accessing'!
 
+domainCode
+
+    ^ self unsignedShortAt:1
+!
+
+domainCode:anInteger
+
+    self unsignedShortAt:1 put:anInteger
+!
+
 hostAddress:anAddress
-    self replaceBytesFrom:1 to:anAddress size with:anAddress startingAt:1
+    "generic method, subclasses usually redefine this"
 
-
+    self replaceBytesFrom:3 to:anAddress size+2 with:anAddress startingAt:1
 !
 
 hostAddress:addr port:portNr
@@ -161,6 +294,29 @@
 
 ! !
 
+!SocketAddress methodsFor:'printing & storing'!
+
+displayString
+    "redefine form 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:aByteArray size 
+         with:aByteArray startingAt:1.
+! !
+
 !SocketAddress methodsFor:'queries'!
 
 address
@@ -168,17 +324,31 @@
 !
 
 hostName
-    ^ self subclassResponsibility
+    ^ (self class getNameInfo:self wantHostName:true 
+                  wantServiceName:false datagram:false flags:0) first
 
-    "Created: 2.11.1995 / 11:17:51 / cg"
+    "
+     (IPSocketAddress hostAddress:#[127 0 0 1] port:7) hostName
+     (IPSocketAddress hostAddress:#[193 141 12 193] port:10) 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.9 1999-09-21 00:27:27 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/SocketAddress.st,v 1.10 2003-03-27 13:30:01 stefan Exp $'
 ! !
--- a/UDSocketAddress.st	Thu Mar 27 14:29:58 2003 +0100
+++ b/UDSocketAddress.st	Thu Mar 27 14:30:01 2003 +0100
@@ -10,8 +10,10 @@
  hereby transferred.
 "
 
+"{ Package: 'stx:libbasic2' }"
+
 SocketAddress variableByteSubclass:#UDSocketAddress
-	instanceVariableNames:'name'
+	instanceVariableNames:''
 	classVariableNames:''
 	poolDictionaries:''
 	category:'OS-Sockets'
@@ -70,28 +72,69 @@
     "
 ! !
 
-!UDSocketAddress methodsFor:'private initialization'!
+!UDSocketAddress class methodsFor:'queries'!
+
+domainSymbol
 
-name: pathName
-    name := pathName
+    ^ #unix
+!
+
+socketAddressSize
+    ^ OperatingSystem socketAccessor socketAddressSize:#unix
 ! !
 
-!UDSocketAddress methodsFor:'queries'!
+!UDSocketAddress methodsFor:'accessing'!
+
+name
+
+    ^ self stringAt:3
+!
+
+name:pathName
+
+    self stringAt:3 put:pathName
+! !
+
+!UDSocketAddress methodsFor:'obsolete'!
 
 address
     ^ nil
 !
 
 hostName
-    ^ 'localhost'
+    ^ 'local'
+!
+
+hostName:hostOrPathName port:portNrOrName
+
+    self name:hostOrPathName
+!
+
+port:pathName
+
+    self name:pathName
 !
 
 portOrName
-    ^ name
+
+    ^ self name
+! !
+
+!UDSocketAddress methodsFor:'printing & storing'!
+
+printOn:aStream
+
+
+    aStream nextPutAll:self class name; 
+            nextPut:$(; nextPutAll:self name; nextPut:$)
+
+    "
+     (self name:'/tmp/abcde') printString
+    "
 ! !
 
 !UDSocketAddress class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic2/UDSocketAddress.st,v 1.7 1999-09-21 00:27:17 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/UDSocketAddress.st,v 1.8 2003-03-27 13:29:59 stefan Exp $'
 ! !