--- a/Socket.st Thu Nov 23 02:24:36 1995 +0100
+++ b/Socket.st Thu Nov 23 02:51:57 1995 +0100
@@ -11,13 +11,117 @@
"
NonPositionableExternalStream subclass:#Socket
- instanceVariableNames:'domain socketType protocol port serviceName
- peerName'
- classVariableNames:''
- poolDictionaries:''
- category:'Streams-External'
+ instanceVariableNames:'domain socketType protocol port serviceName peerName'
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Streams-External'
!
+!Socket primitiveDefinitions!
+%{
+/* #define NO_BUFFER */
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef LINUX
+/* kludge to avoid some redefines ... */
+# define _ARPA_NAMESER_H
+# define _NETINET_TCP_H
+#endif
+
+#ifndef transputer
+# include <fcntl.h>
+# include <sys/types.h>
+
+# if defined(IRIS) && !defined(IRIX5)
+ /* no socket.h on 4.0.5h ?!?!? */
+# define AF_UNIX 1
+# define AF_INET 2
+# define SOCK_STREAM 1
+# define SOCK_DGRAM 2
+# define SOCK_RAW 3
+# else
+# include <sys/socket.h>
+# endif
+
+# ifdef NEXT3
+# include <netinet/in_systm.h>
+# endif
+
+# include <netdb.h>
+# include <netinet/in.h>
+# if ! (defined(SYSV3) && defined(mc88k))
+# include <netinet/tcp.h>
+# endif
+#endif
+
+/*
+ * just in case those PF_xxx's are undefined
+ */
+#ifdef AF_UNIX
+# ifndef PF_UNIX
+# define PF_UNIX AF_UNIX
+# endif
+#endif
+#ifdef AF_INET
+# ifndef PF_INET
+# define PF_INET AF_INET
+# endif
+#endif
+#ifdef AF_DECnet
+# ifndef PF_DECnet
+# define PF_DECnet AF_DECnet
+# endif
+#endif
+#ifdef AF_APPLETALK
+# ifndef PF_APPLETALK
+# define PF_APPLETALK AF_APPLETALK
+# endif
+#endif
+#ifdef AF_X25
+# ifndef PF_X25
+# define PF_X25 AF_X25
+# endif
+#endif
+#ifdef AF_NS
+# ifndef PF_NS
+# define PF_NS AF_NS
+# endif
+#endif
+#ifdef AF_SNA
+# ifndef PF_SNA
+# define PF_SNA AF_SNA
+# endif
+#endif
+#ifdef AF_RAW
+# ifndef PF_RAW
+# define PF_RAW AF_RAW
+# endif
+#endif
+
+#ifdef AF_UNIX
+# include <sys/un.h>
+#endif
+
+/*
+ * on some systems errno is a macro ... check for it here
+ */
+#ifndef errno
+ extern errno;
+#endif
+
+static int __debugging__ = 0;
+
+#ifdef DEBUG
+# define DBGPRINTF(x) { if (__debugging__) printf x; }
+#else
+# define DBGPRINTF(x) /* as nothing */
+#endif
+
+%}
+! !
+
!Socket class methodsFor:'documentation'!
copyright
@@ -34,10 +138,6 @@
"
!
-version
- ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.42 1995-11-13 18:36:22 cg Exp $'
-!
-
documentation
"
This class provides access to (unix-)sockets for interprocess communication.
@@ -301,112 +401,36 @@
] forkAt:(Processor userBackgroundPriority).
walkProcess name:'ping net walker'.
"
+!
+
+version
+ ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.43 1995-11-23 01:51:57 cg Exp $'
! !
-!Socket primitiveDefinitions!
-
-%{
-/* #define NO_BUFFER */
-
-#include <stdio.h>
-#include <errno.h>
-
-#ifdef LINUX
-/* kludge to avoid some redefines ... */
-# define _ARPA_NAMESER_H
-# define _NETINET_TCP_H
-#endif
-
-#ifndef transputer
-# include <fcntl.h>
-# include <sys/types.h>
+!Socket class methodsFor:'ST80 instance creation'!
-# if defined(IRIS) && !defined(IRIX5)
- /* no socket.h on 4.0.5h ?!?!? */
-# define AF_UNIX 1
-# define AF_INET 2
-# define SOCK_STREAM 1
-# define SOCK_DGRAM 2
-# define SOCK_RAW 3
-# else
-# include <sys/socket.h>
-# endif
+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, #ns, #appletalk or #ns;
+ Type must be #stream, #datagram or #raw
-# ifdef NEXT3
-# include <netinet/in_systm.h>
-# endif
+ XXX: currently only the #inet domain is supported"
-# include <netdb.h>
-# include <netinet/in.h>
-# if ! (defined(SYSV3) && defined(mc88k))
-# include <netinet/tcp.h>
-# endif
-#endif
+ ^ self domain:domainSymbol type:typeSymbol
-/*
- * just in case those PF_xxx's are undefined
- */
-#ifdef AF_UNIX
-# ifndef PF_UNIX
-# define PF_UNIX AF_UNIX
-# endif
-#endif
-#ifdef AF_INET
-# ifndef PF_INET
-# define PF_INET AF_INET
-# endif
-#endif
-#ifdef AF_DECnet
-# ifndef PF_DECnet
-# define PF_DECnet AF_DECnet
-# endif
-#endif
-#ifdef AF_APPLETALK
-# ifndef PF_APPLETALK
-# define PF_APPLETALK AF_APPLETALK
-# endif
-#endif
-#ifdef AF_X25
-# ifndef PF_X25
-# define PF_X25 AF_X25
-# endif
-#endif
-#ifdef AF_NS
-# ifndef PF_NS
-# define PF_NS AF_NS
-# endif
-#endif
-#ifdef AF_SNA
-# ifndef PF_SNA
-# define PF_SNA AF_SNA
-# endif
-#endif
-#ifdef AF_RAW
-# ifndef PF_RAW
-# define PF_RAW AF_RAW
-# endif
-#endif
+ "
+ Socket family:#inet type:#stream
+ Socket family:#inet type:#datagram
+ Socket family:#unix type:#stream
+ "
+! !
-#ifdef AF_UNIX
-# include <sys/un.h>
-#endif
+!Socket class methodsFor:'ST80 queries'!
-/*
- * on some systems errno is a macro ... check for it here
- */
-#ifndef errno
- extern errno;
-#endif
+sockStream
+ "return the type code for stream sockets"
-static int __debugging__ = 0;
-
-#ifdef DEBUG
-# define DBGPRINTF(x) { if (__debugging__) printf x; }
-#else
-# define DBGPRINTF(x) /* as nothing */
-#endif
-
-%}
+ ^ #stream
! !
!Socket class methodsFor:'Signal constants'!
@@ -437,8 +461,351 @@
"
! !
+!Socket class methodsFor:'easy tcp/ip instance creation'!
+
+connectTo:service on:host
+ "standard & easy client setup:
+ create new client tcp socket, bind and connect;
+ return the socket.
+ The system may block (interruptable), until the connection is
+ established."
+
+ ^ (self new) for:host port:(self portOfService:service).
+
+ "
+ Socket connectTo:9995 on:'clam'
+ Socket connectTo:'finger' on:'clam'
+ Socket connectTo:'ftp' on:'clam'
+ Socket connectTo:'nntp' on:(OperatingSystem getEnvironment:'NNTPSERVER')
+ "
+!
+
+provide:service
+ "standard & easy server setup:
+ create a new TCP server socket providing a service."
+
+ |newSock|
+
+ newSock := (self new) for:nil port:(self portOfService:service).
+ newSock notNil ifTrue:[
+ newSock listenFor:5.
+ ].
+ ^ newSock
+
+ "
+ Socket provide:9995
+ (Socket provide:9996) accept
+ Socket provide:'nntp'
+ "
+! !
+
+!Socket class methodsFor:'general instance creation'!
+
+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, #ns, #appletalk or #ns;
+ Type must be #stream, #datagram or #raw
+
+ XXX: currently only the #inet domain is supported"
+
+ ^ self new domain:domainSymbol type:type
+
+ "
+ Socket domain:#inet type:#stream
+ Socket domain:#inet type:#datagram
+ Socket domain:#unix type:#stream
+ Socket domain:#appletalk type:#stream
+ Socket domain:#DECnet type:#stream
+ "
+!
+
+newTCP
+ "create a TCP socket - no binding or other setup is done,
+ neither connect nor connect-wait is done."
+
+ ^ self new domain:#inet type:#stream
+
+ "Socket newUDP"
+!
+
+newTCP:aServiceOrNil
+ "create a TCP socket for a service -
+ neither connect nor connect-wait is done."
+
+ |newSock|
+
+ newSock := self newTCP.
+ (newSock notNil and:[aServiceOrNil notNil]) ifTrue:[
+ newSock bindTo:(self portOfService:aServiceOrNil) address:nil
+ ].
+ ^ newSock
+
+
+ "Socket newTCP:'nntp'"
+ "Socket newTCP:9995"
+!
+
+newTCPclientToHost:hostname 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: #newTCPclientToHost:port:withTimeout:"
+
+ ^ self newTCPclientToHost:hostname port:aService withTimeout:nil
+
+ "
+ Socket newTCPclientToHost:'localhost' port:'nntp'
+ "
+
+ "Created: 31.10.1995 / 18:54:11 / cg"
+!
+
+newTCPclientToHost:hostname port:aService withTimeout:millis
+ "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.."
+
+ |newSock|
+
+ newSock := self newTCP.
+ newSock notNil ifTrue:[
+ (newSock connectTo:hostname port:(self portOfService:aService) withTimeout:millis) ifFalse:[
+ newSock close.
+ ^ nil
+ ]
+ ].
+ ^ newSock
+"
+same as:
+ ^ (self new) for:hostname port:(self portOfService:aPort).
+"
+ "
+ Socket newTCPclientToHost:'slsv6bt' port:'nntp'
+ Socket newTCPclientToHost:'localhost' port:'nntp' withTimeout:1000
+ "
+!
+
+newTCPserverAtPort:aService
+ "create a new TCP server socket providing service."
+
+ |newSock|
+
+ newSock := self newTCP.
+ newSock notNil ifTrue:[
+ (newSock bindTo:(self portOfService:aService) address:nil) ifFalse:[
+ ^ nil
+ ]
+ ].
+ ^ newSock
+"
+same as:
+ ^ (self new) for:nil port:aPort
+"
+!
+
+newUDP
+ "create a UDP socket - no binding or other setup is done,
+ neither connect nor connect-wait is done."
+
+ ^ self new domain:#inet type:#datagram
+
+ "Socket newUDP"
+!
+
+newUDP:aServiceOrNil
+ "create a UDP socket for a service -
+ neither connect nor connect-wait is done."
+
+ |newSock|
+
+ newSock := self newUDP.
+ (newSock notNil and:[aServiceOrNil notNil]) ifTrue:[
+ newSock bindTo:(self portOfService:aServiceOrNil) address:nil
+ ].
+ ^ newSock
+
+ "Socket newUDP:nil"
+!
+
+newUDPserverAtPort:aService
+ "create a new UDP server socket providing service."
+
+ |newSock|
+
+ newSock := self newUDP.
+ newSock notNil ifTrue:[
+ (newSock bindTo:(self portOfService:aService) address:nil) ifFalse:[
+ ^ nil
+ ]
+ ].
+ ^ newSock
+"
+same as:
+ ^ (self new) for:nil udpPort:aPort
+"
+!
+
+newUNIX
+ "create a UNIX domain socket - no binding or other setup is done,
+ neither connect nor connect-wait is done."
+
+ ^ self new domain:#unix type:#stream
+
+ "
+ Socket newUNIX
+ "
+!
+
+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).
+ See also: #newUNIXclientTo:withTimeout:"
+
+ ^ self newUNIXclientTo:pathName withTimeout:nil
+
+!
+
+newUNIXclientTo:pathName withTimeout:millis
+ "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.."
+
+ |newSock|
+
+ newSock := self newUNIX.
+ newSock notNil ifTrue:[
+ (newSock connectTo:pathName port:nil withTimeout:millis) ifFalse:[
+ newSock close.
+ ^ nil
+ ]
+ ].
+ ^ newSock
+
+ "
+ |s|
+
+ s := Socket newUNIXclientTo:'/tmp/foo'
+ "
+!
+
+newUNIXserverAt:pathName
+ "create a new UNIX server socket providing service at a pathname."
+
+ |newSock|
+
+ newSock := self newUNIX.
+ newSock notNil ifTrue:[
+ (newSock bindTo:pathName address:nil) ifFalse:[
+ ^ nil
+ ]
+ ].
+ ^ newSock
+
+ "
+ |s s2|
+
+ s := Socket newUNIXserverAt:'/tmp/foo'.
+ s listenFor:5.
+ s2 := s accept.
+ "
+! !
+
!Socket class methodsFor:'queries'!
+domainOfProtocol:aProtocol
+ "given a protocols name (i.e. tcp, udp etc) return the domain.
+ This method needs more ... - or is there a way to get this from the system ?"
+
+ "
+ tcp/ip stuff
+ "
+ (aProtocol = 'tcp') ifTrue:[^ #inet].
+ (aProtocol = 'udp') ifTrue:[^ #inet].
+ (aProtocol = 'ip') ifTrue:[^ #inet].
+ "
+ unix domain
+ "
+ (aProtocol = 'ud') ifTrue:[^ #unix].
+
+ "
+ add x25 stuff (if any) here ...
+ "
+ "
+ add appletalk stuff (if any) here ...
+ "
+ "
+ add other stuff (if any) here ...
+ "
+ ^ nil
+
+ "
+ Socket domainOfProtocol:'tcp'
+ Socket domainOfProtocol:'ucp'
+ Socket domainOfProtocol:(Socket protocolOfService:'nntp')
+ Socket domainOfProtocol:(Socket protocolOfService:'echo')
+ "
+!
+
+hostWithIpAddress:anAddress
+ "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).
+ This is the reverse operation to #ipAddressOfHost:."
+
+ |b1 b2 b3 b4|
+
+ b1 := anAddress at:1.
+ b2 := anAddress at:2.
+ b3 := anAddress at:3.
+ b4 := anAddress at:4.
+%{
+ struct sockaddr_in sa ;
+ struct hostent *hp ;
+
+ if (__bothSmallInteger(b1, b2) && __bothSmallInteger(b3, b4)) {
+ bzero(&sa, sizeof(sa)) ;
+ sa.sin_addr.s_addr = _intVal(b1) & 0xFF;
+ sa.sin_addr.s_addr = (sa.sin_addr.s_addr << 8) | (_intVal(b2) & 0xFF);
+ sa.sin_addr.s_addr = (sa.sin_addr.s_addr << 8) | (_intVal(b3) & 0xFF);
+ sa.sin_addr.s_addr = (sa.sin_addr.s_addr << 8) | (_intVal(b4) & 0xFF);
+ sa.sin_addr.s_addr = htonl(sa.sin_addr.s_addr);
+ sa.sin_family = AF_INET;
+ /* do we know the host's address? */
+ hp = gethostbyaddr((char *) &sa.sin_addr.s_addr, sizeof(sa.sin_addr.s_addr), AF_INET);
+ if (hp == NULL) {
+ DBGPRINTF(("SOCKET: unknown address: %d.%d.%d.%d\n",
+ _intVal(b1), _intVal(b2), _intVal(b3), _intVal(b4)));
+ } else {
+ sa.sin_family = hp->h_addrtype;
+ }
+ }
+
+ /* if the addressing family is not AF_INET, return nil */
+ if (sa.sin_family != AF_INET) {
+ RETURN ( nil );
+ }
+ if (hp != NULL)
+ RETURN (_MKSTRING(hp->h_name COMMA_CON));
+
+ RETURN (_MKSTRING(inet_ntoa(sa.sin_addr) COMMA_CON));
+%}
+
+ "
+ Socket ipAddressOfHost:'clam'
+ Socket hostWithIpAddress:(Socket ipAddressOfHost:'clam')
+ Socket ipAddressOfHost:'porty'
+ Socket hostWithIpAddress:(Socket ipAddressOfHost:'porty')
+ Socket hostWithIpAddress:#[1 2 3 4]
+ Socket hostWithIpAddress:(Socket ipAddressOfHost:'1.2.3.4')
+ "
+!
+
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).
@@ -496,60 +863,6 @@
"
!
-hostWithIpAddress:anAddress
- "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).
- This is the reverse operation to #ipAddressOfHost:."
-
- |b1 b2 b3 b4|
-
- b1 := anAddress at:1.
- b2 := anAddress at:2.
- b3 := anAddress at:3.
- b4 := anAddress at:4.
-%{
- struct sockaddr_in sa ;
- struct hostent *hp ;
-
- if (__bothSmallInteger(b1, b2) && __bothSmallInteger(b3, b4)) {
- bzero(&sa, sizeof(sa)) ;
- sa.sin_addr.s_addr = _intVal(b1) & 0xFF;
- sa.sin_addr.s_addr = (sa.sin_addr.s_addr << 8) | (_intVal(b2) & 0xFF);
- sa.sin_addr.s_addr = (sa.sin_addr.s_addr << 8) | (_intVal(b3) & 0xFF);
- sa.sin_addr.s_addr = (sa.sin_addr.s_addr << 8) | (_intVal(b4) & 0xFF);
- sa.sin_addr.s_addr = htonl(sa.sin_addr.s_addr);
- sa.sin_family = AF_INET;
- /* do we know the host's address? */
- hp = gethostbyaddr((char *) &sa.sin_addr.s_addr, sizeof(sa.sin_addr.s_addr), AF_INET);
- if (hp == NULL) {
- DBGPRINTF(("SOCKET: unknown address: %d.%d.%d.%d\n",
- _intVal(b1), _intVal(b2), _intVal(b3), _intVal(b4)));
- } else {
- sa.sin_family = hp->h_addrtype;
- }
- }
-
- /* if the addressing family is not AF_INET, return nil */
- if (sa.sin_family != AF_INET) {
- RETURN ( nil );
- }
- if (hp != NULL)
- RETURN (_MKSTRING(hp->h_name COMMA_CON));
-
- RETURN (_MKSTRING(inet_ntoa(sa.sin_addr) COMMA_CON));
-%}
-
- "
- Socket ipAddressOfHost:'clam'
- Socket hostWithIpAddress:(Socket ipAddressOfHost:'clam')
- Socket ipAddressOfHost:'porty'
- Socket hostWithIpAddress:(Socket ipAddressOfHost:'porty')
- Socket hostWithIpAddress:#[1 2 3 4]
- Socket hostWithIpAddress:(Socket ipAddressOfHost:'1.2.3.4')
- "
-!
-
portOfService:aNameOrNumber
"returns the port-number for a given service
or nil if no such service exists;
@@ -655,40 +968,6 @@
"
!
-domainOfProtocol:aProtocol
- "given a protocols name (i.e. tcp, udp etc) return the domain.
- This method needs more ... - or is there a way to get this from the system ?"
-
- "
- tcp/ip stuff
- "
- (aProtocol = 'tcp') ifTrue:[^ #inet].
- (aProtocol = 'udp') ifTrue:[^ #inet].
- (aProtocol = 'ip') ifTrue:[^ #inet].
- "
- unix domain
- "
- (aProtocol = 'ud') ifTrue:[^ #unix].
-
- "
- add x25 stuff (if any) here ...
- "
- "
- add appletalk stuff (if any) here ...
- "
- "
- add other stuff (if any) here ...
- "
- ^ nil
-
- "
- Socket domainOfProtocol:'tcp'
- Socket domainOfProtocol:'ucp'
- Socket domainOfProtocol:(Socket protocolOfService:'nntp')
- Socket domainOfProtocol:(Socket protocolOfService:'echo')
- "
-!
-
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 ?"
@@ -719,729 +998,410 @@
"
! !
-!Socket class methodsFor:'easy tcp/ip instance creation'!
-
-connectTo:service on:host
- "standard & easy client setup:
- create new client tcp socket, bind and connect;
- return the socket.
- The system may block (interruptable), until the connection is
- established."
+!Socket methodsFor:'ST-80 mimicri'!
- ^ (self new) for:host port:(self portOfService:service).
-
- "
- Socket connectTo:9995 on:'clam'
- Socket connectTo:'finger' on:'clam'
- Socket connectTo:'ftp' on:'clam'
- Socket connectTo:'nntp' on:(OperatingSystem getEnvironment:'NNTPSERVER')
- "
+errorReporter
+ ^ self
!
-provide:service
- "standard & easy server setup:
- create a new TCP server socket providing a service."
-
- |newSock|
-
- newSock := (self new) for:nil port:(self portOfService:service).
- newSock notNil ifTrue:[
- newSock listenFor:5.
- ].
- ^ newSock
-
- "
- Socket provide:9995
- (Socket provide:9996) accept
- Socket provide:'nntp'
- "
-! !
-
-!Socket class methodsFor:'ST80 queries'!
+notReadySignal
+ "for now - this is not yet raised"
-sockStream
- "return the type code for stream sockets"
-
- ^ #stream
-! !
-
-!Socket class methodsFor:'ST80 instance creation'!
-
-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, #ns, #appletalk or #ns;
- Type must be #stream, #datagram or #raw
-
- XXX: currently only the #inet domain is supported"
-
- ^ self domain:domainSymbol type:typeSymbol
-
- "
- Socket family:#inet type:#stream
- Socket family:#inet type:#datagram
- Socket family:#unix type:#stream
- "
+ ^ Signal new
! !
-!Socket class methodsFor:'general instance creation'!
-
-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, #ns, #appletalk or #ns;
- Type must be #stream, #datagram or #raw
-
- XXX: currently only the #inet domain is supported"
-
- ^ self new domain:domainSymbol type:type
-
- "
- Socket domain:#inet type:#stream
- Socket domain:#inet type:#datagram
- Socket domain:#unix type:#stream
- Socket domain:#appletalk type:#stream
- Socket domain:#DECnet type:#stream
- "
-!
-
-newUDP
- "create a UDP socket - no binding or other setup is done,
- neither connect nor connect-wait is done."
-
- ^ self new domain:#inet type:#datagram
-
- "Socket newUDP"
-!
-
-newUDP:aServiceOrNil
- "create a UDP socket for a service -
- neither connect nor connect-wait is done."
-
- |newSock|
-
- newSock := self newUDP.
- (newSock notNil and:[aServiceOrNil notNil]) ifTrue:[
- newSock bindTo:(self portOfService:aServiceOrNil) address:nil
- ].
- ^ newSock
+!Socket methodsFor:'datagram transmission'!
- "Socket newUDP:nil"
-!
-
-newTCP
- "create a TCP socket - no binding or other setup is done,
- neither connect nor connect-wait is done."
-
- ^ self new domain:#inet type:#stream
-
- "Socket newUDP"
-!
-
-newTCP:aServiceOrNil
- "create a TCP socket for a service -
- neither connect nor connect-wait is done."
-
- |newSock|
+receiveFrom:anAddressBuffer buffer:aDataBuffer
+ "receive datagramm data - put address of originating host into
+ anAddressBuffer, data into aBuffer.
+ Both must be ByteArray-like. The addressBuffer must
+ provide space for a valid address for my domain (i.e. for inet, a 4-byte byteArray).
+ Return the number of bytes received, or a negative number on error.
+ On error, the unix error code is left in the lastErrorNumber
+ instance variable."
- newSock := self newTCP.
- (newSock notNil and:[aServiceOrNil notNil]) ifTrue:[
- newSock bindTo:(self portOfService:aServiceOrNil) address:nil
- ].
- ^ newSock
-
-
- "Socket newTCP:'nntp'"
- "Socket newTCP:9995"
-!
-
-newTCPclientToHost:hostname 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: #newTCPclientToHost:port:withTimeout:"
-
- ^ self newTCPclientToHost:hostname port:aService withTimeout:nil
-
- "
- Socket newTCPclientToHost:'localhost' port:'nntp'
- "
-
- "Created: 31.10.1995 / 18:54:11 / cg"
+ ^ self receiveFrom:anAddressBuffer buffer:aDataBuffer start:1 for:(aDataBuffer size)
!
-newTCPclientToHost:hostname port:aService withTimeout:millis
- "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.."
+receiveFrom:anAddressBuffer buffer:aDataBuffer start:startIndex for:nBytes
+ "receive datagramm data - put address of originating host into
+ anAddressBuffer, data into aBuffer. For ST-80 compatibility,
+ the addressBuffer may be a non-ByteArray; then, it must understand
+ the addressBytes-message (i.e. be a SocketAddress instance).
+ Return the number of bytes received, or a negative number on error.
+ On error, the unix error code is left in the lastErrorNumber
+ instance variable."
+
+ |addrBytes addrLen nReceived|
- |newSock|
+ addrBytes := ByteArray new:100.
+%{
+ OBJ oClass;
+ OBJ fp = _INST(filePointer);
+ int nInstVars, nInstBytes, objSize;
+ int sock;
+ struct sockaddr_in sa ;
+ int alen;
+ int n;
+ char *cp;
+ int flags = 0;
+
+ if (fp != nil) {
+ sock = fileno(__FILEVal(fp));
- newSock := self newTCP.
- newSock notNil ifTrue:[
- (newSock connectTo:hostname port:(self portOfService:aService) withTimeout:millis) ifFalse:[
- newSock close.
- ^ nil
- ]
- ].
- ^ newSock
-"
-same as:
- ^ (self new) for:hostname port:(self portOfService:aPort).
-"
- "
- Socket newTCPclientToHost:'slsv6bt' port:'nntp'
- Socket newTCPclientToHost:'localhost' port:'nntp' withTimeout:1000
- "
-!
+ oClass = __Class(aDataBuffer);
+ switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
+ case BYTEARRAY:
+ case WORDARRAY:
+ case LONGARRAY:
+ case FLOATARRAY:
+ case DOUBLEARRAY:
+ break;
+ default:
+ goto bad;
+ }
-newTCPserverAtPort:aService
- "create a new TCP server socket providing service."
-
- |newSock|
+ nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
+ nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
+ objSize = _Size(aDataBuffer) - nInstBytes;
+ cp = (char *)_InstPtr(aDataBuffer) + nInstBytes;
+ if (__isSmallInteger(startIndex)) {
+ cp += __intVal(startIndex);
+ objSize -= __intVal(startIndex);
+ }
+ if (__isSmallInteger(nBytes)) {
+ if (__intVal(nBytes) < objSize) {
+ objSize = __intVal(nBytes);
+ }
+ }
- newSock := self newTCP.
- newSock notNil ifTrue:[
- (newSock bindTo:(self portOfService:aService) address:nil) ifFalse:[
- ^ nil
- ]
- ].
- ^ newSock
-"
-same as:
- ^ (self new) for:nil port:aPort
-"
-!
-
-newUDPserverAtPort:aService
- "create a new UDP server socket providing service."
-
- |newSock|
+ __BEGIN_INTERRUPTABLE__
+ do {
+ if (addrBytes == nil) {
+ n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) 0, 0);
+ } else {
+ n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) &sa, &alen);
+ }
+ } while ((n < 0) && (errno == EINTR));
+ __END_INTERRUPTABLE__
- newSock := self newUDP.
- newSock notNil ifTrue:[
- (newSock bindTo:(self portOfService:aService) address:nil) ifFalse:[
- ^ nil
- ]
+ if (n >= 0) {
+ if (addrBytes != nil) {
+ oClass = __Class(addrBytes);
+ if ((_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) != BYTEARRAY)
+ goto bad;
+ nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
+ nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
+ objSize = _Size(addrBytes) - nInstBytes;
+ cp = (char *)_InstPtr(addrBytes) + nInstBytes;
+ if (objSize < alen)
+ goto bad;
+ bcopy((char *)&sa, cp, alen);
+ addrLen = _MKSMALLINT(alen);
+ }
+ }
+ if (n < 0) {
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ }
+ nReceived = _MKSMALLINT(n);
+ }
+bad: ;
+%}.
+ nReceived notNil ifTrue:[
+ nReceived < 0 ifTrue:[
+ (OperatingSystem errorTextForNumber:lastErrorNumber) printNL.
+ ].
+ addrLen notNil ifTrue:[
+ anAddressBuffer class isBytes ifTrue:[
+ anAddressBuffer replaceFrom:1 to:addrLen with:addrBytes
+ ] ifFalse:[
+ "/ can be SocketAddress for ST-80 compatibility
+ anAddressBuffer addressBytes:(addrBytes copyTo:addrLen)
+ ].
+ ].
+ ^ nReceived
].
- ^ newSock
-"
-same as:
- ^ (self new) for:nil udpPort:aPort
-"
-!
-
-newUNIX
- "create a UNIX domain socket - no binding or other setup is done,
- neither connect nor connect-wait is done."
-
- ^ self new domain:#unix type:#stream
-
"
- Socket newUNIX
+ arrive here if you try to receive into an invalid buffer
+ (i.e. not ByteArray-like),
+ or if the addressBuffer is nonNil AND not a ByteArray/String
+ or if the addressBuffer is nonNil AND too small.
"
+ self primitiveFailed
!
-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).
- See also: #newUNIXclientTo:withTimeout:"
-
- ^ self newUNIXclientTo:pathName withTimeout:nil
-
-!
-
-newUNIXclientTo:pathName withTimeout:millis
- "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.."
+sendTo:anAddressBuffer buffer:buffer
+ "send datagramm data - fetch address of destination host from
+ anAddressBuffer, data from aDataBuffer.
+ Both must be ByteArray-like. The bytes in the addressBuffer must
+ be a valid address for my domain (i.e. for inet, a 4-byte byteArray).
+ Return the number of bytes transmitted, or a negative number on error.
+ On error, the unix error code is left in the lastErrorNumber
+ instance variable.
+ Flags is currently ignored; it is there for ST-80 compatibility."
- |newSock|
-
- newSock := self newUNIX.
- newSock notNil ifTrue:[
- (newSock connectTo:pathName port:nil withTimeout:millis) ifFalse:[
- newSock close.
- ^ nil
- ]
- ].
- ^ newSock
-
- "
- |s|
-
- s := Socket newUNIXclientTo:'/tmp/foo'
- "
+ ^ self sendTo:anAddressBuffer buffer:buffer start:1 for:buffer size flags:0
!
-newUNIXserverAt:pathName
- "create a new UNIX server socket providing service at a pathname."
-
- |newSock|
-
- newSock := self newUNIX.
- newSock notNil ifTrue:[
- (newSock bindTo:pathName address:nil) ifFalse:[
- ^ nil
- ]
- ].
- ^ newSock
-
- "
- |s s2|
-
- s := Socket newUNIXserverAt:'/tmp/foo'.
- s listenFor:5.
- s2 := s accept.
- "
-! !
+sendTo:anAddressBuffer buffer:aDataBuffer start:startIndex for:count flags:flags
+ "send datagramm data - fetch address of destination host from
+ anAddressBuffer, data from aDataBuffer starting at startIndex,
+ sending count bytes.
+ Both must be ByteArray-like. The bytes in the addressBuffer must
+ be a valid address for my domain (i.e. for inet, a 4-byte byteArray).
+ Return the number of bytes transmitted, or a negative number on error.
+ On error, the unix error code is left in the lastErrorNumber
+ instance variable."
-!Socket methodsFor:'socket setup'!
-
-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
- #inet,#unix, #appletalk, #x25 .. and #stream, #datagram, #raw resp."
-
- ^ self domain:domainArg type:typeArg protocol:0
-!
+ |addrBytes addrLen nReceived portNo|
-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
- #inet,#unix, #appletalk, #x25 .. and #stream, #datagram, #raw resp."
-
- |errorNr|
-
- filePointer notNil ifTrue:[
- ^ self error:'already created'
+ "/ addressBuffer can be a 6-byte byteArray (last 2 bytes are portNo, msb-first)
+ "/ or an instance of IPSocketAddress
+ "/
+ anAddressBuffer class isBytes ifTrue:[
+ addrBytes := anAddressBuffer copyFrom:1 to:4.
+ portNo := ((anAddressBuffer at:5) bitShift:8)
+ + (anAddressBuffer at:6).
+ ] ifFalse:[
+ addrBytes := anAddressBuffer hostAddress.
+ portNo := anAddressBuffer port.
].
%{
- FILE *fp;
- int dom, typ, pf, proto = 0, sock;
-
- if (! __isSymbol(domainArg)) {
- DBGPRINTF(("SOCKET: bad domain\n"));
- RETURN ( nil );
- }
- if (! __isSymbol(typeArg)) {
- DBGPRINTF(("SOCKET: bad type\n"));
- RETURN ( nil );
- }
- if (protocolNumber != nil) {
- if (!__isSmallInteger(protocolNumber)) {
- DBGPRINTF(("SOCKET: bad protocol\n"));
- RETURN ( nil );
- }
- proto = __intVal(protocolNumber);
- }
-
+ OBJ oClass;
+ OBJ fp = _INST(filePointer);
+ int nInstVars, nInstBytes, objSize;
+ int sock;
+ struct sockaddr_in sa;
+ struct sockaddr *saPtr = (struct sockaddr *)&sa;
+ int alen = sizeof(sa);
+ int n;
+ char *cp;
+ int _flags = 0;
+ int offs, nBytes;
+ unsigned long norder;
- /*
- * get address and protocol-family
- */
-#ifdef AF_UNIX
- if (domainArg == @symbol(unix)) {
- dom = AF_UNIX;
- } else
-#endif
-#ifdef AF_INET
- if (domainArg == @symbol(inet)) {
- dom = AF_INET;
- } else
-#endif
-#ifdef AF_DECnet
- if (domainArg == @symbol(DECnet)) {
- dom = AF_DECnet;
- } else
-#endif
-#ifdef AF_APPLETALK
- if (domainArg == @symbol(appletalk)) {
- dom = AF_APPLETALK;
- } else
-#endif
-#ifdef AF_X25
- if (domainArg == @symbol(x25)) {
- dom = AF_X25;
- } else
-#endif
-#ifdef AF_NS
- if (domainArg == @symbol(xns)) {
- dom = AF_NS;
- } else
-#endif
-#ifdef AF_SNA
- if (domainArg == @symbol(sna)) {
- dom = AF_SNA;
- } else
-#endif
-#ifdef AF_RAW
- if (domainArg == @symbol(raw)) {
- dom = AF_RAW;
- } else
-#endif
- {
- DBGPRINTF(("SOCKET: unknown domain <%s>\n", _stringVal(domainArg)));
- RETURN ( nil );
- }
+ _flags = __longIntVal(flags);
+
+ if ((fp != nil)
+ && __isSmallInteger(startIndex)
+ && __isSmallInteger(count)) {
+ sock = fileno(__FILEVal(fp));
-#ifdef SOCK_STREAM
- if (typeArg == @symbol(stream)) {
- typ = SOCK_STREAM;
- } else
-#endif
-#ifdef SOCK_DGRAM
- if (typeArg == @symbol(datagram)) {
- typ = SOCK_DGRAM;
- } else
-#endif
-#ifdef SOCK_RAW
- if (typeArg == @symbol(raw))
- typ = SOCK_RAW;
- else
-#endif
-#ifdef SOCK_SEQPACKET
- if (typeArg == @symbol(seqPacket))
- typ = SOCK_SEQPACKET;
- else
-#endif
- {
- DBGPRINTF(("SOCKET: bad type <%s>\n", _stringVal(typeArg)));
- RETURN ( nil );
- }
-
- __BEGIN_INTERRUPTABLE__
- do {
- DBGPRINTF(("SOCKET: opening socket domain=%d type=%d proto=%d\n", dom, typ, proto));
- sock = socket(dom, typ, proto);
-#if defined(EPROTONOSUPPORT) /* for SGI */
- if ((proto != 0) && (sock < 0) && (errno == EPROTONOSUPPORT)) {
- DBGPRINTF(("SOCKET: retry with UNSPEC protocol\n"));
- proto = 0;
- sock = socket(dom, typ, 0);
+ if (addrBytes != nil) {
+ if (! __isByteArray(addrBytes)) goto bad;
+ cp = __ByteArrayInstPtr(addrBytes)->ba_element;
+ n = __byteArraySize(addrBytes);
+ if (alen < n) n = alen;
+/*
+printf("address is %d bytes ... %d.%d.%d.%d", n, cp[0], cp[1], cp[2], cp[3]);
+*/
+ bcopy(cp, &sa.sin_addr.s_addr, n);
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons((u_short) __intVal(portNo));
+ } else {
+ alen = 0;
+ saPtr = (struct sockaddr *)0;
}
-#endif
- } while ((sock < 0) && (errno == EINTR));
- __END_INTERRUPTABLE__
- if (sock < 0) {
- DBGPRINTF(("SOCKET: socket(dom=%d typ=%d proto=%d) call failed errno=%d\n", dom, typ, proto, errno));
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- } else {
- /*
- * make it a FILE *
- */
- fp = fdopen(sock, "r+");
- if (! fp) {
- DBGPRINTF(("SOCKET: fdopen call failed\n"));
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- __BEGIN_INTERRUPTABLE__
- close(sock);
- __END_INTERRUPTABLE__
- } else {
- _INST(filePointer) = __MKOBJ(fp);
+ oClass = __Class(aDataBuffer);
+ switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
+ case BYTEARRAY:
+ offs = __intVal(startIndex) - 1;
+ break;
+ case WORDARRAY:
+ offs = (__intVal(startIndex) - 1) * sizeof(short);
+ break;
+ case LONGARRAY:
+ offs = (__intVal(startIndex) - 1) * sizeof(long);
+ break;
+ case FLOATARRAY:
+ offs = (__intVal(startIndex) - 1) * sizeof(float);
+ break;
+ case DOUBLEARRAY:
+ offs = (__intVal(startIndex) - 1) * sizeof(double);
+#ifdef NEED_DOUBLE_ALIGN
+ offs += sizeof(long);
+#endif
+ break;
+ default:
+ goto bad;
}
- }
-%}.
-
- "all ok?"
- filePointer notNil ifTrue:[
- domain := domainArg.
- socketType := typeArg.
- ] ifFalse:[
- ^ nil
- ].
-
- "
- Socket new domain:#inet type:#stream
- Socket new domain:#unix type:#stream
- "
-!
-
-for:hostName udpPort:portNr
- "setup for a UDP socket (i.e. inet domain, datagram type)
- if hostname is nil, a server port is opened;
- otherwise a client port to the server on host.
-
- HISTORIC LEFTOVER:
- This method will vanish, as soon as the low level
- connect/bind works,"
-
- self obsoleteMethodWarning.
+ nBytes = __intVal(count);
- filePointer notNil ifTrue:[
- ^ self error:'already created'
- ].
- (portNr isMemberOf:SmallInteger) ifFalse:[
- ^ self error:'invalid portNr'
- ].
-%{
- struct sockaddr_in sa ;
- struct hostent *hp ;
- int a, sock ;
- long addr;
- FILE *fp;
- int ret;
+ nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
+ nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
+ objSize = __qSize(aDataBuffer) - nInstBytes;
+ cp = (char *)_InstPtr(aDataBuffer) + nInstBytes;
+ cp += offs;
+ if ((offs + nBytes) > objSize) {
+/*
+printf("cut off ...\n");
+*/
+ nBytes = objSize - offs;
+ }
- if (hostName != nil) {
- bzero(&sa, sizeof(sa)) ;
- if ((addr = inet_addr((char *) _stringVal(hostName))) != -1) {
- /*
- * is Internet addr in octet notation
- */
- bcopy(&addr, (char *) &sa.sin_addr, sizeof(addr)) ; /* set address */
- sa.sin_family = AF_INET ;
- } else {
- /*
- * is hostname -
- * do we know the host's address?
- */
- if ((hp = gethostbyname((char *) _stringVal(hostName))) == NULL) {
- DBGPRINTF(("SOCKET: unknown host\n"));
- RETURN ( nil );
- }
- bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length) ;
- sa.sin_family = hp->h_addrtype ;
- }
- } else
- sa.sin_family = AF_INET;
+ norder = htonl(sa.sin_addr.s_addr);
+/*
+printf("sending %d bytes ... to ", nBytes);
+printf("%d.%d.%d.%d\n",
+ (norder >> 24) & 0xFF,
+ (norder >> 16) & 0xFF,
+ (norder >> 8) & 0xFF,
+ norder & 0xFF);
+*/
- /*
- * create the socket
- */
- __BEGIN_INTERRUPTABLE__
- do {
- sock = socket(sa.sin_family, SOCK_DGRAM, 0);
- } while ((sock < 0) && (errno == EINTR));
- __END_INTERRUPTABLE__
-
- if (sock < 0) {
- DBGPRINTF(("SOCKET: socket(dom=%d typ=%d proto=0) call failed errno=%d\n", sa.sin_family, SOCK_DGRAM, errno));
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- } else {
- /*
- * ok,
- * connect/bind
- */
__BEGIN_INTERRUPTABLE__
- if (hostName == nil) {
- sa.sin_addr.s_addr = htonl(INADDR_ANY);
- do {
- ret = bind(sock, (struct sockaddr *)&sa, sizeof(sa));
- } while ((ret < 0) && (errno == EINTR));
- } else {
- sa.sin_port = htons((u_short) _intVal(portNr)) ;
- do {
- ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa));
- } while ((ret < 0) && (errno == EINTR));
- }
+ do {
+ n = sendto(sock, cp, nBytes, _flags, saPtr, alen);
+ } while ((n < 0) && (errno == EINTR));
__END_INTERRUPTABLE__
- if (ret < 0) {
- DBGPRINTF(("SOCKET: bind/connect call failed\n"));
+ if (n < 0) {
_INST(lastErrorNumber) = _MKSMALLINT(errno);
- __BEGIN_INTERRUPTABLE__
- close(sock) ;
- __END_INTERRUPTABLE__
- } else {
- /*
- * make it a FILE *
- */
- fp = fdopen(sock, "r+");
- if (! fp) {
- DBGPRINTF(("SOCKET: fdopen call failed\n"));
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- __BEGIN_INTERRUPTABLE__
- close(sock);
- __END_INTERRUPTABLE__
- } else {
-#ifdef NO_BUFFER
- setbuf(fp, NULL);
- _INST(buffered) = false;
-#endif
- _INST(filePointer) = __MKOBJ(fp);
- }
}
+ RETURN (_MKSMALLINT(n));
}
+bad: ;
%}.
- filePointer isNil ifTrue:[
- ^ nil
- ].
-
- mode := #readwrite.
- binary := false.
-
- domain := #inet.
- socketType := #datagram.
- protocol := portNr.
- peerName := hostName.
-
- "
- Socket new for:'clam' udpPort:(Socket portOfService:'echo')
"
-!
-
-for:hostName port:portNr
- "setup for a TCP socket (i.e. inet domain, stream type)
- If hostname is nil, a server port is opened,
- otherwise a client port to the server on host.
-
- HISTORIC LEFTOVER:
- This method will vanish, as soon as the low level
- connect/bind works,"
-
- self obsoleteMethodWarning.
-
- filePointer notNil ifTrue:[
- ^ self error:'already created'
- ].
- (portNr isMemberOf:SmallInteger) ifFalse:[
- ^ self error:'invalid portNr'
- ].
-%{
- struct sockaddr_in sa ;
- struct hostent *hp ;
- int a, sock ;
- long addr;
- FILE *fp;
- int ret;
- int on = 1;
-
- bzero((char *) &sa, sizeof(sa)) ;
- sa.sin_family = AF_INET;
- sa.sin_addr.s_addr = htonl(INADDR_ANY);
-
- if ((hostName != nil) && __isString(hostName)){
- bzero(&sa, sizeof(sa)) ;
- if ((addr = inet_addr((char *) _stringVal(hostName))) != -1) {
- /*
- * is Internet addr in octet notation
- */
- bcopy(&addr, (char *) &sa.sin_addr, sizeof(addr)) ; /* set address */
- } else {
- /*
- * do we know the host's address?
- */
- if ((hp = gethostbyname((char *) _stringVal(hostName))) == NULL) {
- DBGPRINTF(("SOCKET: unknown host\n"));
- RETURN ( nil );
- }
- bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length) ;
- sa.sin_family = hp->h_addrtype;
- }
- }
-
- /*
- * create the socket
- */
- __BEGIN_INTERRUPTABLE__
- do {
- sock = socket(sa.sin_family, SOCK_STREAM, 0);
- } while ((sock < 0) && (errno == EINTR));
- __END_INTERRUPTABLE__
-
- if (sock < 0) {
- DBGPRINTF(("SOCKET: socket(dom=%d typ=%d proto=0) call failed errno=%d\n", sa.sin_family, SOCK_STREAM, errno));
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- } else {
- /*
- * connect/bind
- */
- sa.sin_port = htons((u_short) _intVal(portNr)) ;
-
- __BEGIN_INTERRUPTABLE__
- if (hostName != nil) {
- do {
- ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa));
- } while ((ret < 0) && (errno == EINTR));
- } else {
-#ifdef SO_REUSEADDR
- /*
- * should I also do this for DGRAM sockets ?
- */
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
- DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n"));
- }
-#endif /* SO_REUSEADDR */
- sa.sin_addr.s_addr = htonl(INADDR_ANY);
- do {
- ret = bind(sock, (struct sockaddr *)&sa, sizeof(sa));
- } while ((ret < 0) && (errno == EINTR));
- }
- __END_INTERRUPTABLE__
-
- if (ret < 0) {
- DBGPRINTF(("SOCKET: bind/connect call failed errno=%d\n", errno));
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- __BEGIN_INTERRUPTABLE__
- close(sock) ;
- __END_INTERRUPTABLE__
- } else {
- /*
- * make it a FILE *
- */
- fp = fdopen(sock, "r+");
- if (! fp) {
- DBGPRINTF(("SOCKET: fdopen failed\n"));
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- __BEGIN_INTERRUPTABLE__
- close(sock);
- __END_INTERRUPTABLE__
- } else {
-#ifdef NO_BUFFER
- setbuf(fp, NULL);
- _INST(buffered) = false;
-#endif
- _INST(filePointer) = __MKOBJ(fp);
- }
- }
- }
-%}.
- filePointer isNil ifTrue:[
- ^ nil
- ].
- mode := #readwrite.
- binary := false.
-
- domain := #inet.
- socketType := #stream.
- protocol := portNr.
- peerName := hostName.
-
+ arrive here if you try to send from an invalid buffer
+ (i.e. not ByteArray-like),
+ or if the addressBuffer is nonNil AND not a ByteArray/String
+ or if the addressBuffer is nonNil AND too small.
"
- Socket new for:'clam' port:(Socket portOfService:'echo')
-
- Socket new for:nil port:9999
- Socket new for:(OperatingSystem getHostName) port:9999
- "
+ self primitiveFailed
! !
!Socket methodsFor:'low level'!
-closeFile
- "low level close"
+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"
+
+ |newSock|
+
+"/ self readWait.
+ newSock := self class new.
+ (newSock acceptOn:self) ifFalse:[^ nil].
+ ^ newSock
+
+ "
+ |sock newSock|
+
+ sock := Socket provide:8004.
+ sock listenFor:5.
+ newSock := sock accept.
+ "
+!
+
+acceptOn:aSocket
+ "accept a connection on a server port (created with:'Socket>>onIPPort:')
+ usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)).
+ Return the true if ok; false if not.
+
+ NOTICE: this method will block, if no connection is already pending.
+ use readWait or Socket>>accept."
-%{ /* NOCONTEXT */
+ |serverSocketFd|
+
+ filePointer notNil ifTrue:[
+ ^ self error:'already connected'
+ ].
- OBJ t;
+ domain := aSocket domain.
+ socketType := aSocket type.
+ serverSocketFd := aSocket fileDescriptor.
+ serverSocketFd isNil ifTrue:[
+ ^ self error:'invalid server socket'
+ ].
+ (serverSocketFd isMemberOf:SmallInteger) ifFalse:[
+ ^ self error:'invalid server socket'
+ ].
+%{
+ FILE *fp;
+ int flags;
+ int sock, newSock;
+ union {
+ struct sockaddr_in in ;
+ struct sockaddr_un un ;
+ } sa;
+ int alen;
+ struct hostent *he ;
+ char dotted[20] ;
+
+ sock = _intVal(serverSocketFd);
- t = _INST(filePointer);
- if (t != nil) {
- FILE *fp;
+#if defined(O_NDELAY) && defined(SET_NDELAY)
+ flags = ioctl(sock, F_GETFL, 0);
+ ioctl(sock, F_SETFL, flags | O_NDELAY);
+#endif
+ __BEGIN_INTERRUPTABLE__
+ do {
+ alen = sizeof(sa) ;
+ newSock = accept(sock, (struct sockaddr *) &sa, &alen);
+ } while ((newSock < 0) && (errno == EINTR));
+ __END_INTERRUPTABLE__
+
+#if defined(O_NDELAY) && defined(SET_NDELAY)
+ ioctl(sock, F_SETFL, flags);
+#endif
+
+ if (newSock < 0) {
+ DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ RETURN (false);
+ }
+
+ /*
+ * extract the partners address
+ */
+#ifdef AF_INET
+ if (_INST(domain) == @symbol(inet)) {
+ he = gethostbyaddr((char *) &sa.in.sin_addr.s_addr, alen, AF_INET) ;
+ if (! he) {
+ unsigned long norder;
- fp = __FILEVal(t);
- fflush(fp);
- shutdown(fileno(fp), 2);
- fclose(fp);
- _INST(filePointer) = nil;
+ norder = htonl(sa.in.sin_addr.s_addr) ;
+ sprintf(dotted, "%d.%d.%d.%d",
+ (norder >> 24) & 0xFF,
+ (norder >> 16) & 0xFF,
+ (norder >> 8) & 0xFF,
+ norder & 0xFF);
+ }
+ DBGPRINTF(("SOCKET: accepted connection from host %s\n", (he ? he->h_name : dotted))) ;
+ _INST(peerName) = _MKSTRING((he ? he->h_name : dotted) COMMA_CON);
+ }
+#endif
+#ifdef AF_UNIX
+ if (_INST(domain) == @symbol(unix)) {
+ DBGPRINTF(("SOCKET: accepted connection on unix socket\n")) ;
+ /* nothing to be done here */
}
-%}
+#endif
+
+ /*
+ * make it a FILE *
+ */
+ fp = fdopen(newSock, "r+");
+ if (! fp) {
+ DBGPRINTF(("SOCKET: fdopen call failed\n"));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ close(newSock);
+ RETURN (false);
+ } else {
+#ifdef NO_BUFFER
+ setbuf(fp, NULL);
+ _INST(buffered) = false;
+#endif
+ _INST(filePointer) = __MKOBJ(fp);
+ }
+%}.
+ mode := #readwrite.
+ binary := false.
+ port := aSocket port.
+ ^ true
!
bindTo:aSocketAddress
@@ -1615,31 +1575,24 @@
"
!
-connectTo:hostOrPathName port:portNrOrName withTimeout:millis
- "connect to port, portNrOrName on host, hostName.
- Or path (UNIX socket), where portNrOrName is ignored.
- Return true if ok, false otherwise.
- Hostname must be a string, portNrOrName an integer port number (in inet domain).
- If a non-nil timeout is given, stop trying after that time and return false as well."
+closeFile
+ "low level close"
- |stopSignal stopMe connection|
+%{ /* NOCONTEXT */
+
+ OBJ t;
- millis isNil ifTrue:[
- ^ self connectTo:hostOrPathName port:portNrOrName
- ].
- stopSignal := Signal new.
- stopMe := [stopSignal raise].
- stopSignal handle:[:ex |
-"/ 'timeout on connect' infoPrintNL.
- ^ false
- ] do:[
- Processor addTimedBlock:stopMe afterMilliseconds:millis.
- connection := self connectTo:hostOrPathName port:portNrOrName.
- Processor removeTimedBlock:stopMe.
- ].
- ^ connection
+ t = _INST(filePointer);
+ if (t != nil) {
+ FILE *fp;
- "Created: 31.10.1995 / 18:52:49 / cg"
+ fp = __FILEVal(t);
+ fflush(fp);
+ shutdown(fileno(fp), 2);
+ fclose(fp);
+ _INST(filePointer) = nil;
+ }
+%}
!
connectTo:hostOrPathName port:portNrOrName
@@ -1814,6 +1767,39 @@
^ true
!
+connectTo:hostOrPathName port:portNrOrName withTimeout:millis
+ "connect to port, portNrOrName on host, hostName.
+ Or path (UNIX socket), where portNrOrName is ignored.
+ Return true if ok, false otherwise.
+ Hostname must be a string, portNrOrName an integer port number (in inet domain).
+ If a non-nil timeout is given, stop trying after that time and return false as well."
+
+ |stopSignal stopMe connection|
+
+ millis isNil ifTrue:[
+ ^ self connectTo:hostOrPathName port:portNrOrName
+ ].
+ stopSignal := Signal new.
+ stopMe := [stopSignal raise].
+ stopSignal handle:[:ex |
+"/ 'timeout on connect' infoPrintNL.
+ ^ false
+ ] do:[
+ Processor addTimedBlock:stopMe afterMilliseconds:millis.
+ connection := self connectTo:hostOrPathName port:portNrOrName.
+ Processor removeTimedBlock:stopMe.
+ ].
+ ^ connection
+
+ "Created: 31.10.1995 / 18:52:49 / cg"
+!
+
+listenFor:aNumber
+ "same as listenWithBacklog: - for ST-80 compatibility"
+
+ ^ self listenWithBacklog:aNumber
+!
+
listenWithBacklog:aNumber
"start listening; return true if ok, false on error"
@@ -1845,145 +1831,22 @@
}
%}.
^ true
-!
-
-listenFor:aNumber
- "same as listenWithBacklog: - for ST-80 compatibility"
-
- ^ self listenWithBacklog:aNumber
-!
-
-acceptOn:aSocket
- "accept a connection on a server port (created with:'Socket>>onIPPort:')
- usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)).
- Return the true if ok; false if not.
-
- NOTICE: this method will block, if no connection is already pending.
- use readWait or Socket>>accept."
-
- |serverSocketFd|
-
- filePointer notNil ifTrue:[
- ^ self error:'already connected'
- ].
-
- domain := aSocket domain.
- socketType := aSocket type.
- serverSocketFd := aSocket fileDescriptor.
- serverSocketFd isNil ifTrue:[
- ^ self error:'invalid server socket'
- ].
- (serverSocketFd isMemberOf:SmallInteger) ifFalse:[
- ^ self error:'invalid server socket'
- ].
-%{
- FILE *fp;
- int flags;
- int sock, newSock;
- union {
- struct sockaddr_in in ;
- struct sockaddr_un un ;
- } sa;
- int alen;
- struct hostent *he ;
- char dotted[20] ;
-
- sock = _intVal(serverSocketFd);
-
-#if defined(O_NDELAY) && defined(SET_NDELAY)
- flags = ioctl(sock, F_GETFL, 0);
- ioctl(sock, F_SETFL, flags | O_NDELAY);
-#endif
- __BEGIN_INTERRUPTABLE__
- do {
- alen = sizeof(sa) ;
- newSock = accept(sock, (struct sockaddr *) &sa, &alen);
- } while ((newSock < 0) && (errno == EINTR));
- __END_INTERRUPTABLE__
-
-#if defined(O_NDELAY) && defined(SET_NDELAY)
- ioctl(sock, F_SETFL, flags);
-#endif
-
- if (newSock < 0) {
- DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno));
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- RETURN (false);
- }
-
- /*
- * extract the partners address
- */
-#ifdef AF_INET
- if (_INST(domain) == @symbol(inet)) {
- he = gethostbyaddr((char *) &sa.in.sin_addr.s_addr, alen, AF_INET) ;
- if (! he) {
- unsigned long norder;
-
- norder = htonl(sa.in.sin_addr.s_addr) ;
- sprintf(dotted, "%d.%d.%d.%d",
- (norder >> 24) & 0xFF,
- (norder >> 16) & 0xFF,
- (norder >> 8) & 0xFF,
- norder & 0xFF);
- }
- DBGPRINTF(("SOCKET: accepted connection from host %s\n", (he ? he->h_name : dotted))) ;
- _INST(peerName) = _MKSTRING((he ? he->h_name : dotted) COMMA_CON);
- }
-#endif
-#ifdef AF_UNIX
- if (_INST(domain) == @symbol(unix)) {
- DBGPRINTF(("SOCKET: accepted connection on unix socket\n")) ;
- /* nothing to be done here */
- }
-#endif
-
- /*
- * make it a FILE *
- */
- fp = fdopen(newSock, "r+");
- if (! fp) {
- DBGPRINTF(("SOCKET: fdopen call failed\n"));
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- close(newSock);
- RETURN (false);
- } else {
-#ifdef NO_BUFFER
- setbuf(fp, NULL);
- _INST(buffered) = false;
-#endif
- _INST(filePointer) = __MKOBJ(fp);
- }
-%}.
- mode := #readwrite.
- binary := false.
- port := aSocket port.
- ^ true
-!
-
-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"
-
- |newSock|
-
-"/ self readWait.
- newSock := self class new.
- (newSock acceptOn:self) ifFalse:[^ nil].
- ^ newSock
-
- "
- |sock newSock|
-
- sock := Socket provide:8004.
- sock listenFor:5.
- newSock := sock accept.
- "
! !
!Socket methodsFor:'queries'!
+domain
+ "return the sockets addressing domain (i.e. #inet, #unix, #x25, #appletalk)"
+
+ ^ domain
+!
+
+getName
+ "return the name; here, we return the ports name"
+
+ ^ port printString
+!
+
getPeer
"ST-80 compatibility: return an IPSocketAddress instance representing
my hostname/port combination.
@@ -2004,10 +1867,10 @@
^ peerName
!
-getName
- "return the name; here, we return the ports name"
+isActive
+ "return true, if the receiver has a connection"
- ^ port printString
+ ^ filePointer notNil
!
port
@@ -2016,66 +1879,436 @@
^ port
!
-domain
- "return the sockets addressing domain (i.e. #inet, #unix, #x25, #appletalk)"
-
- ^ domain
-!
-
type
"return the sockets connection type (i.e. #datagram, #stream etc)"
^ socketType
-!
-
-isActive
- "return true, if the receiver has a connection"
-
- ^ filePointer notNil
! !
-!Socket methodsFor:'ST-80 mimicri'!
+!Socket methodsFor:'socket setup'!
+
+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
+ #inet,#unix, #appletalk, #x25 .. and #stream, #datagram, #raw resp."
+
+ ^ self domain:domainArg type:typeArg protocol:0
+!
+
+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
+ #inet,#unix, #appletalk, #x25 .. and #stream, #datagram, #raw resp."
+
+ |errorNr|
+
+ filePointer notNil ifTrue:[
+ ^ self error:'already created'
+ ].
+%{
+ FILE *fp;
+ int dom, typ, pf, proto = 0, sock;
+
+ if (! __isSymbol(domainArg)) {
+ DBGPRINTF(("SOCKET: bad domain\n"));
+ RETURN ( nil );
+ }
+ if (! __isSymbol(typeArg)) {
+ DBGPRINTF(("SOCKET: bad type\n"));
+ RETURN ( nil );
+ }
+ if (protocolNumber != nil) {
+ if (!__isSmallInteger(protocolNumber)) {
+ DBGPRINTF(("SOCKET: bad protocol\n"));
+ RETURN ( nil );
+ }
+ proto = __intVal(protocolNumber);
+ }
+
-errorReporter
- ^ self
+ /*
+ * get address and protocol-family
+ */
+#ifdef AF_UNIX
+ if (domainArg == @symbol(unix)) {
+ dom = AF_UNIX;
+ } else
+#endif
+#ifdef AF_INET
+ if (domainArg == @symbol(inet)) {
+ dom = AF_INET;
+ } else
+#endif
+#ifdef AF_DECnet
+ if (domainArg == @symbol(DECnet)) {
+ dom = AF_DECnet;
+ } else
+#endif
+#ifdef AF_APPLETALK
+ if (domainArg == @symbol(appletalk)) {
+ dom = AF_APPLETALK;
+ } else
+#endif
+#ifdef AF_X25
+ if (domainArg == @symbol(x25)) {
+ dom = AF_X25;
+ } else
+#endif
+#ifdef AF_NS
+ if (domainArg == @symbol(xns)) {
+ dom = AF_NS;
+ } else
+#endif
+#ifdef AF_SNA
+ if (domainArg == @symbol(sna)) {
+ dom = AF_SNA;
+ } else
+#endif
+#ifdef AF_RAW
+ if (domainArg == @symbol(raw)) {
+ dom = AF_RAW;
+ } else
+#endif
+ {
+ DBGPRINTF(("SOCKET: unknown domain <%s>\n", _stringVal(domainArg)));
+ RETURN ( nil );
+ }
+
+#ifdef SOCK_STREAM
+ if (typeArg == @symbol(stream)) {
+ typ = SOCK_STREAM;
+ } else
+#endif
+#ifdef SOCK_DGRAM
+ if (typeArg == @symbol(datagram)) {
+ typ = SOCK_DGRAM;
+ } else
+#endif
+#ifdef SOCK_RAW
+ if (typeArg == @symbol(raw))
+ typ = SOCK_RAW;
+ else
+#endif
+#ifdef SOCK_SEQPACKET
+ if (typeArg == @symbol(seqPacket))
+ typ = SOCK_SEQPACKET;
+ else
+#endif
+ {
+ DBGPRINTF(("SOCKET: bad type <%s>\n", _stringVal(typeArg)));
+ RETURN ( nil );
+ }
+
+ __BEGIN_INTERRUPTABLE__
+ do {
+ DBGPRINTF(("SOCKET: opening socket domain=%d type=%d proto=%d\n", dom, typ, proto));
+ sock = socket(dom, typ, proto);
+#if defined(EPROTONOSUPPORT) /* for SGI */
+ if ((proto != 0) && (sock < 0) && (errno == EPROTONOSUPPORT)) {
+ DBGPRINTF(("SOCKET: retry with UNSPEC protocol\n"));
+ proto = 0;
+ sock = socket(dom, typ, 0);
+ }
+#endif
+ } while ((sock < 0) && (errno == EINTR));
+ __END_INTERRUPTABLE__
+
+ if (sock < 0) {
+ DBGPRINTF(("SOCKET: socket(dom=%d typ=%d proto=%d) call failed errno=%d\n", dom, typ, proto, errno));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ } else {
+ /*
+ * make it a FILE *
+ */
+ fp = fdopen(sock, "r+");
+ if (! fp) {
+ DBGPRINTF(("SOCKET: fdopen call failed\n"));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ __BEGIN_INTERRUPTABLE__
+ close(sock);
+ __END_INTERRUPTABLE__
+ } else {
+ _INST(filePointer) = __MKOBJ(fp);
+ }
+ }
+%}.
+
+ "all ok?"
+ filePointer notNil ifTrue:[
+ domain := domainArg.
+ socketType := typeArg.
+ ] ifFalse:[
+ ^ nil
+ ].
+
+ "
+ Socket new domain:#inet type:#stream
+ Socket new domain:#unix type:#stream
+ "
!
-notReadySignal
- "for now - this is not yet raised"
+for:hostName port:portNr
+ "setup for a TCP socket (i.e. inet domain, stream type)
+ If hostname is nil, a server port is opened,
+ otherwise a client port to the server on host.
+
+ HISTORIC LEFTOVER:
+ This method will vanish, as soon as the low level
+ connect/bind works,"
+
+ self obsoleteMethodWarning.
+
+ filePointer notNil ifTrue:[
+ ^ self error:'already created'
+ ].
+ (portNr isMemberOf:SmallInteger) ifFalse:[
+ ^ self error:'invalid portNr'
+ ].
+%{
+ struct sockaddr_in sa ;
+ struct hostent *hp ;
+ int a, sock ;
+ long addr;
+ FILE *fp;
+ int ret;
+ int on = 1;
+
+ bzero((char *) &sa, sizeof(sa)) ;
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if ((hostName != nil) && __isString(hostName)){
+ bzero(&sa, sizeof(sa)) ;
+ if ((addr = inet_addr((char *) _stringVal(hostName))) != -1) {
+ /*
+ * is Internet addr in octet notation
+ */
+ bcopy(&addr, (char *) &sa.sin_addr, sizeof(addr)) ; /* set address */
+ } else {
+ /*
+ * do we know the host's address?
+ */
+ if ((hp = gethostbyname((char *) _stringVal(hostName))) == NULL) {
+ DBGPRINTF(("SOCKET: unknown host\n"));
+ RETURN ( nil );
+ }
+ bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length) ;
+ sa.sin_family = hp->h_addrtype;
+ }
+ }
+
+ /*
+ * create the socket
+ */
+ __BEGIN_INTERRUPTABLE__
+ do {
+ sock = socket(sa.sin_family, SOCK_STREAM, 0);
+ } while ((sock < 0) && (errno == EINTR));
+ __END_INTERRUPTABLE__
+
+ if (sock < 0) {
+ DBGPRINTF(("SOCKET: socket(dom=%d typ=%d proto=0) call failed errno=%d\n", sa.sin_family, SOCK_STREAM, errno));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ } else {
+ /*
+ * connect/bind
+ */
+ sa.sin_port = htons((u_short) _intVal(portNr)) ;
+
+ __BEGIN_INTERRUPTABLE__
+ if (hostName != nil) {
+ do {
+ ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa));
+ } while ((ret < 0) && (errno == EINTR));
+ } else {
+#ifdef SO_REUSEADDR
+ /*
+ * should I also do this for DGRAM sockets ?
+ */
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
+ DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n"));
+ }
+#endif /* SO_REUSEADDR */
+ sa.sin_addr.s_addr = htonl(INADDR_ANY);
+ do {
+ ret = bind(sock, (struct sockaddr *)&sa, sizeof(sa));
+ } while ((ret < 0) && (errno == EINTR));
+ }
+ __END_INTERRUPTABLE__
+
+ if (ret < 0) {
+ DBGPRINTF(("SOCKET: bind/connect call failed errno=%d\n", errno));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ __BEGIN_INTERRUPTABLE__
+ close(sock) ;
+ __END_INTERRUPTABLE__
+ } else {
+ /*
+ * make it a FILE *
+ */
+ fp = fdopen(sock, "r+");
+ if (! fp) {
+ DBGPRINTF(("SOCKET: fdopen failed\n"));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ __BEGIN_INTERRUPTABLE__
+ close(sock);
+ __END_INTERRUPTABLE__
+ } else {
+#ifdef NO_BUFFER
+ setbuf(fp, NULL);
+ _INST(buffered) = false;
+#endif
+ _INST(filePointer) = __MKOBJ(fp);
+ }
+ }
+ }
+%}.
+ filePointer isNil ifTrue:[
+ ^ nil
+ ].
+ mode := #readwrite.
+ binary := false.
+
+ domain := #inet.
+ socketType := #stream.
+ protocol := portNr.
+ peerName := hostName.
- ^ Signal new
+ "
+ Socket new for:'clam' port:(Socket portOfService:'echo')
+
+ Socket new for:nil port:9999
+ Socket new for:(OperatingSystem getHostName) port:9999
+ "
+!
+
+for:hostName udpPort:portNr
+ "setup for a UDP socket (i.e. inet domain, datagram type)
+ if hostname is nil, a server port is opened;
+ otherwise a client port to the server on host.
+
+ HISTORIC LEFTOVER:
+ This method will vanish, as soon as the low level
+ connect/bind works,"
+
+ self obsoleteMethodWarning.
+
+ filePointer notNil ifTrue:[
+ ^ self error:'already created'
+ ].
+ (portNr isMemberOf:SmallInteger) ifFalse:[
+ ^ self error:'invalid portNr'
+ ].
+%{
+ struct sockaddr_in sa ;
+ struct hostent *hp ;
+ int a, sock ;
+ long addr;
+ FILE *fp;
+ int ret;
+
+ if (hostName != nil) {
+ bzero(&sa, sizeof(sa)) ;
+ if ((addr = inet_addr((char *) _stringVal(hostName))) != -1) {
+ /*
+ * is Internet addr in octet notation
+ */
+ bcopy(&addr, (char *) &sa.sin_addr, sizeof(addr)) ; /* set address */
+ sa.sin_family = AF_INET ;
+ } else {
+ /*
+ * is hostname -
+ * do we know the host's address?
+ */
+ if ((hp = gethostbyname((char *) _stringVal(hostName))) == NULL) {
+ DBGPRINTF(("SOCKET: unknown host\n"));
+ RETURN ( nil );
+ }
+ bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length) ;
+ sa.sin_family = hp->h_addrtype ;
+ }
+ } else
+ sa.sin_family = AF_INET;
+
+ /*
+ * create the socket
+ */
+ __BEGIN_INTERRUPTABLE__
+ do {
+ sock = socket(sa.sin_family, SOCK_DGRAM, 0);
+ } while ((sock < 0) && (errno == EINTR));
+ __END_INTERRUPTABLE__
+
+ if (sock < 0) {
+ DBGPRINTF(("SOCKET: socket(dom=%d typ=%d proto=0) call failed errno=%d\n", sa.sin_family, SOCK_DGRAM, errno));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ } else {
+ /*
+ * ok,
+ * connect/bind
+ */
+ __BEGIN_INTERRUPTABLE__
+ if (hostName == nil) {
+ sa.sin_addr.s_addr = htonl(INADDR_ANY);
+ do {
+ ret = bind(sock, (struct sockaddr *)&sa, sizeof(sa));
+ } while ((ret < 0) && (errno == EINTR));
+ } else {
+ sa.sin_port = htons((u_short) _intVal(portNr)) ;
+ do {
+ ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa));
+ } while ((ret < 0) && (errno == EINTR));
+ }
+ __END_INTERRUPTABLE__
+
+ if (ret < 0) {
+ DBGPRINTF(("SOCKET: bind/connect call failed\n"));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ __BEGIN_INTERRUPTABLE__
+ close(sock) ;
+ __END_INTERRUPTABLE__
+ } else {
+ /*
+ * make it a FILE *
+ */
+ fp = fdopen(sock, "r+");
+ if (! fp) {
+ DBGPRINTF(("SOCKET: fdopen call failed\n"));
+ _INST(lastErrorNumber) = _MKSMALLINT(errno);
+ __BEGIN_INTERRUPTABLE__
+ close(sock);
+ __END_INTERRUPTABLE__
+ } else {
+#ifdef NO_BUFFER
+ setbuf(fp, NULL);
+ _INST(buffered) = false;
+#endif
+ _INST(filePointer) = __MKOBJ(fp);
+ }
+ }
+ }
+%}.
+ filePointer isNil ifTrue:[
+ ^ nil
+ ].
+
+ mode := #readwrite.
+ binary := false.
+
+ domain := #inet.
+ socketType := #datagram.
+ protocol := portNr.
+ peerName := hostName.
+
+ "
+ Socket new for:'clam' udpPort:(Socket portOfService:'echo')
+ "
! !
!Socket methodsFor:'specials'!
-sendTimeout:seconds
- "set the send timeout - for special applications only.
- Not all operatingSystems offer this functionality
- (returns false, if unsupported)"
-
- |millis|
-
- filePointer isNil ifTrue:[
- ^ self error:'not a valid socket'
- ].
- millis := (seconds * 1000) rounded.
-%{
-#if defined(SO_SNDTIMEO) && defined(SOL_SOCKET) && defined(HZ)
- if (__isSmallInteger(millis)) {
- OBJ fp = _INST(filePointer);
- int sock;
- int opt;
-
- sock = fileno(__FILEVal(fp));
- opt = _intVal(millis) / (1000 / HZ);
- setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&opt, sizeof(int));
- RETURN(true);
- }
-#endif
-%}.
- ^ false
-!
-
receiveTimeout:seconds
"set the receive timeout - for special applications only.
Not all operatingSystems offer this functionality
@@ -2102,267 +2335,33 @@
#endif
%}.
^ false
-! !
-
-!Socket methodsFor:'datagram transmission'!
-
-receiveFrom:anAddressBuffer buffer:aDataBuffer start:startIndex for:nBytes
- "receive datagramm data - put address of originating host into
- anAddressBuffer, data into aBuffer. For ST-80 compatibility,
- the addressBuffer may be a non-ByteArray; then, it must understand
- the addressBytes-message (i.e. be a SocketAddress instance).
- Return the number of bytes received, or a negative number on error.
- On error, the unix error code is left in the lastErrorNumber
- instance variable."
-
- |addrBytes addrLen nReceived|
-
- addrBytes := ByteArray new:100.
-%{
- OBJ oClass;
- OBJ fp = _INST(filePointer);
- int nInstVars, nInstBytes, objSize;
- int sock;
- struct sockaddr_in sa ;
- int alen;
- int n;
- char *cp;
- int flags = 0;
-
- if (fp != nil) {
- sock = fileno(__FILEVal(fp));
-
- oClass = __Class(aDataBuffer);
- switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
- case BYTEARRAY:
- case WORDARRAY:
- case LONGARRAY:
- case FLOATARRAY:
- case DOUBLEARRAY:
- break;
- default:
- goto bad;
- }
-
- nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
- nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
- objSize = _Size(aDataBuffer) - nInstBytes;
- cp = (char *)_InstPtr(aDataBuffer) + nInstBytes;
- if (__isSmallInteger(startIndex)) {
- cp += __intVal(startIndex);
- objSize -= __intVal(startIndex);
- }
- if (__isSmallInteger(nBytes)) {
- if (__intVal(nBytes) < objSize) {
- objSize = __intVal(nBytes);
- }
- }
-
- __BEGIN_INTERRUPTABLE__
- do {
- if (addrBytes == nil) {
- n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) 0, 0);
- } else {
- n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) &sa, &alen);
- }
- } while ((n < 0) && (errno == EINTR));
- __END_INTERRUPTABLE__
-
- if (n >= 0) {
- if (addrBytes != nil) {
- oClass = __Class(addrBytes);
- if ((_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) != BYTEARRAY)
- goto bad;
- nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
- nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
- objSize = _Size(addrBytes) - nInstBytes;
- cp = (char *)_InstPtr(addrBytes) + nInstBytes;
- if (objSize < alen)
- goto bad;
- bcopy((char *)&sa, cp, alen);
- addrLen = _MKSMALLINT(alen);
- }
- }
- if (n < 0) {
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- }
- nReceived = _MKSMALLINT(n);
- }
-bad: ;
-%}.
- nReceived notNil ifTrue:[
- nReceived < 0 ifTrue:[
- (OperatingSystem errorTextForNumber:lastErrorNumber) printNL.
- ].
- addrLen notNil ifTrue:[
- anAddressBuffer class isBytes ifTrue:[
- anAddressBuffer replaceFrom:1 to:addrLen with:addrBytes
- ] ifFalse:[
- "/ can be SocketAddress for ST-80 compatibility
- anAddressBuffer addressBytes:(addrBytes copyTo:addrLen)
- ].
- ].
- ^ nReceived
- ].
- "
- arrive here if you try to receive into an invalid buffer
- (i.e. not ByteArray-like),
- or if the addressBuffer is nonNil AND not a ByteArray/String
- or if the addressBuffer is nonNil AND too small.
- "
- self primitiveFailed
-!
-
-receiveFrom:anAddressBuffer buffer:aDataBuffer
- "receive datagramm data - put address of originating host into
- anAddressBuffer, data into aBuffer.
- Both must be ByteArray-like. The addressBuffer must
- provide space for a valid address for my domain (i.e. for inet, a 4-byte byteArray).
- Return the number of bytes received, or a negative number on error.
- On error, the unix error code is left in the lastErrorNumber
- instance variable."
-
- ^ self receiveFrom:anAddressBuffer buffer:aDataBuffer start:1 for:(aDataBuffer size)
!
-sendTo:anAddressBuffer buffer:buffer
- "send datagramm data - fetch address of destination host from
- anAddressBuffer, data from aDataBuffer.
- Both must be ByteArray-like. The bytes in the addressBuffer must
- be a valid address for my domain (i.e. for inet, a 4-byte byteArray).
- Return the number of bytes transmitted, or a negative number on error.
- On error, the unix error code is left in the lastErrorNumber
- instance variable.
- Flags is currently ignored; it is there for ST-80 compatibility."
-
- ^ self sendTo:anAddressBuffer buffer:buffer start:1 for:buffer size flags:0
-!
-
-sendTo:anAddressBuffer buffer:aDataBuffer start:startIndex for:count flags:flags
- "send datagramm data - fetch address of destination host from
- anAddressBuffer, data from aDataBuffer starting at startIndex,
- sending count bytes.
- Both must be ByteArray-like. The bytes in the addressBuffer must
- be a valid address for my domain (i.e. for inet, a 4-byte byteArray).
- Return the number of bytes transmitted, or a negative number on error.
- On error, the unix error code is left in the lastErrorNumber
- instance variable."
-
- |addrBytes addrLen nReceived portNo|
+sendTimeout:seconds
+ "set the send timeout - for special applications only.
+ Not all operatingSystems offer this functionality
+ (returns false, if unsupported)"
- "/ addressBuffer can be a 6-byte byteArray (last 2 bytes are portNo, msb-first)
- "/ or an instance of IPSocketAddress
- "/
- anAddressBuffer class isBytes ifTrue:[
- addrBytes := anAddressBuffer copyFrom:1 to:4.
- portNo := ((anAddressBuffer at:5) bitShift:8)
- + (anAddressBuffer at:6).
- ] ifFalse:[
- addrBytes := anAddressBuffer hostAddress.
- portNo := anAddressBuffer port.
- ].
-%{
- OBJ oClass;
- OBJ fp = _INST(filePointer);
- int nInstVars, nInstBytes, objSize;
- int sock;
- struct sockaddr_in sa;
- struct sockaddr *saPtr = (struct sockaddr *)&sa;
- int alen = sizeof(sa);
- int n;
- char *cp;
- int _flags = 0;
- int offs, nBytes;
- unsigned long norder;
-
- _flags = __longIntVal(flags);
-
- if ((fp != nil)
- && __isSmallInteger(startIndex)
- && __isSmallInteger(count)) {
- sock = fileno(__FILEVal(fp));
+ |millis|
- if (addrBytes != nil) {
- if (! __isByteArray(addrBytes)) goto bad;
- cp = __ByteArrayInstPtr(addrBytes)->ba_element;
- n = __byteArraySize(addrBytes);
- if (alen < n) n = alen;
-/*
-printf("address is %d bytes ... %d.%d.%d.%d", n, cp[0], cp[1], cp[2], cp[3]);
-*/
- bcopy(cp, &sa.sin_addr.s_addr, n);
- sa.sin_family = AF_INET;
- sa.sin_port = htons((u_short) __intVal(portNo));
- } else {
- alen = 0;
- saPtr = (struct sockaddr *)0;
- }
-
- oClass = __Class(aDataBuffer);
- switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
- case BYTEARRAY:
- offs = __intVal(startIndex) - 1;
- break;
- case WORDARRAY:
- offs = (__intVal(startIndex) - 1) * sizeof(short);
- break;
- case LONGARRAY:
- offs = (__intVal(startIndex) - 1) * sizeof(long);
- break;
- case FLOATARRAY:
- offs = (__intVal(startIndex) - 1) * sizeof(float);
- break;
- case DOUBLEARRAY:
- offs = (__intVal(startIndex) - 1) * sizeof(double);
-#ifdef NEED_DOUBLE_ALIGN
- offs += sizeof(long);
-#endif
- break;
- default:
- goto bad;
- }
- nBytes = __intVal(count);
+ filePointer isNil ifTrue:[
+ ^ self error:'not a valid socket'
+ ].
+ millis := (seconds * 1000) rounded.
+%{
+#if defined(SO_SNDTIMEO) && defined(SOL_SOCKET) && defined(HZ)
+ if (__isSmallInteger(millis)) {
+ OBJ fp = _INST(filePointer);
+ int sock;
+ int opt;
- nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
- nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
- objSize = __qSize(aDataBuffer) - nInstBytes;
- cp = (char *)_InstPtr(aDataBuffer) + nInstBytes;
- cp += offs;
- if ((offs + nBytes) > objSize) {
-/*
-printf("cut off ...\n");
-*/
- nBytes = objSize - offs;
- }
-
- norder = htonl(sa.sin_addr.s_addr);
-/*
-printf("sending %d bytes ... to ", nBytes);
-printf("%d.%d.%d.%d\n",
- (norder >> 24) & 0xFF,
- (norder >> 16) & 0xFF,
- (norder >> 8) & 0xFF,
- norder & 0xFF);
-*/
+ sock = fileno(__FILEVal(fp));
+ opt = _intVal(millis) / (1000 / HZ);
+ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&opt, sizeof(int));
+ RETURN(true);
+ }
+#endif
+%}.
+ ^ false
+! !
- __BEGIN_INTERRUPTABLE__
- do {
- n = sendto(sock, cp, nBytes, _flags, saPtr, alen);
- } while ((n < 0) && (errno == EINTR));
- __END_INTERRUPTABLE__
-
- if (n < 0) {
- _INST(lastErrorNumber) = _MKSMALLINT(errno);
- }
- RETURN (_MKSMALLINT(n));
- }
-bad: ;
-%}.
- "
- arrive here if you try to send from an invalid buffer
- (i.e. not ByteArray-like),
- or if the addressBuffer is nonNil AND not a ByteArray/String
- or if the addressBuffer is nonNil AND too small.
- "
- self primitiveFailed
-! !