--- a/Socket.st Thu Jun 02 13:35:26 1994 +0200
+++ b/Socket.st Thu Jun 02 13:36:39 1994 +0200
@@ -23,7 +23,7 @@
COPYRIGHT (c) 1992 by Claus Gittinger
All Rights Reserved
-$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.8 1994-04-13 00:33:10 claus Exp $
+$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.9 1994-06-02 11:36:14 claus Exp $
'!
%{
@@ -39,7 +39,16 @@
#ifndef transputer
# include <fcntl.h>
# include <sys/types.h>
-# include <sys/socket.h>
+# ifdef IRIS
+ /* 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
# include <netdb.h>
# include <netinet/in.h>
# if ! (defined(SYSV3) && defined(mc88k))
@@ -58,6 +67,55 @@
Also, currently there is almost no support for other than IP
sockets - this will be added in the future.
+ Due to historic reasons (I started this class, before I got hold of some
+ code using ST-80 Sockets i.e. RemoteInvocation), there is some old interface
+ still provided. This will vanish; use the newTCPxxx and newUDPxxx interface, which
+ is meant to be compatible to ST-80's UnixSocketAccessor interface.
+
+ example (get help info from an nntp server):
+
+ |sock|
+
+ sock := Socket newTCPclientToHost:(OperatingSystem getEnvironment:'NNTPSERVER') port:'nntp'.
+ Transcript showCr:sock nextLine.
+ sock buffered:false.
+
+ sock nextPutAll:'HELP'; cr.
+ [:exit |
+ |line|
+
+ line := sock nextLine.
+ line = '.' ifTrue:[exit value:nil].
+ Transcript showCr:line.
+ ] loopWithExit.
+ sock close
+
+ example (connect to an ftp server):
+
+ |sock|
+
+ sock := Socket newTCPclientToHost:(OperatingSystem getHostName) port:'ftp'.
+
+ sock buffered:false.
+ Transcript showCr:sock nextLine.
+ sock nextPutAll:('USER ' , OperatingSystem getLoginName); cr.
+ Transcript showCr:sock nextLine.
+ sock nextPutAll:('PASS ' , 'bettimaus' "'a password here'"); cr.
+ Transcript showCr:sock nextLine.
+ sock nextPutAll:'LIST'; cr.
+ Transcript showCr:sock nextLine.
+
+ "dont know enough of the ftp protocol by to continue here ..."
+
+ example (connect to an snmp server):
+
+ |sock|
+
+ sock := Socket newUDP:'snpm'.
+ sock connectTo:(OperatingSystem getHostName).
+ sock buffered:false.
+ Transcript showCr:got it'.
+
"
! !
@@ -72,100 +130,6 @@
^ PipeStream brokenPipeSignal
! !
-!Socket class methodsFor:'standard instance creation'!
-
-connectTo:service on:host
- "standard setup: create new client tcp socket, bind and connect;
- return the socket.
- The system will 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:'nntp' on:'nntphost'
- "
-!
-
-provide:service
- "standard setup: create a new TCP server socket providing 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 class methodsFor:'general instance creation'!
-
-domain:domainSymbol type:type protocol:aProtocolOrNil
- "create a socket for domain, type and protocol -
- neither connect nor connect-wait is done."
-
- ^ self new domain:domainSymbol type:type protocol:aProtocolOrNil
-
- "Socket domain:#inet type:#datagram protocol:nil"
-!
-
-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 protocol:nil
-
- "Socket newUDP"
-!
-
-newUDP:aProtocolOrNil
- "create a UDP socket for protocol -
- neither connect nor connect-wait is done."
-
- ^ self new domain:#inet type:#datagram protocol:aProtocolOrNil
-
- "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:#datagram protocol:nil
-
- "Socket newUDP"
-!
-
-newTCP:aProtocolOrNil
- "create a TCP socket for protocol -
- neither connect nor connect-wait is done."
-
- ^ self new domain:#inet type:#stream protocol:aProtocolOrNil
-
- "Socket newTCP:'nntp'"
- "Socket newTCP:9995"
-!
-
-newTCPserverAtPort:aPort
- "create a new TCP server socket providing service."
-
- ^ (self new) for:nil port:aPort
-!
-
-newUDPserverAtPort:aPort
- "create a new UDP server socket providing service."
-
- ^ (self new) for:nil udpPort:aPort
-! !
-
!Socket class methodsFor:'queries'!
ipAddressOfHost:aHostName
@@ -278,19 +242,22 @@
if (__isString(aNameOrNumber)) {
servent = getservbyname((char *) _stringVal(aNameOrNumber), "tcp");
if (servent != NULL) {
- RETURN ( _MKSMALLINT(servent->s_port) );
+ RETURN ( _MKSMALLINT(ntohs(servent->s_port)) );
}
RETURN ( nil );
}
RETURN ( nil );
%}
- "Socket portOfService:'finger'"
- "Socket portOfService:'nntp'"
+ "
+ Socket portOfService:'finger'
+ Socket portOfService:'nntp'
+ Socket portOfService:'echo'
+ "
!
protocolOfService:aNameOrNumber
"returns the protocol (as string) for a given service
- or nil if no such service exists"
+ or nil if no such service exists."
%{
struct servent *servent = NULL;
@@ -318,10 +285,220 @@
}
RETURN ( nil );
%}
- "Socket protocolOfService:'finger'"
- "Socket protocolOfService:'nntp'"
- "Socket protocolOfService:'xxx'"
- "Socket protocolOfService:79"
+ "
+ Socket protocolOfService:'finger'
+ Socket protocolOfService:'nntp'
+ Socket protocolOfService:'xxx'
+ Socket protocolOfService:79
+ "
+!
+
+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].
+ "
+ x25 stuff (if any)
+ appletalk stuff (if any)
+ other stuff (if any)
+ "
+ ^ 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 ?"
+
+ (aProtocol = 'tcp') ifTrue:[^ #stream].
+ (aProtocol = 'udp') ifTrue:[^ #datagram].
+ (aProtocol = 'ip') ifTrue:[^ #raw].
+ "
+ x25 stuff (if any)
+ appletalk stuff (if any)
+ other stuff (if any)
+ "
+ ^ nil
+
+ "
+ Socket typeOfProtocol:'tcp'
+ Socket typeOfProtocol:'ucp'
+ Socket typeOfProtocol:(Socket protocolOfService:'nntp')
+ Socket typeOfProtocol:(Socket protocolOfService:'echo')
+ "
+! !
+
+!Socket class methodsFor:'tcp/ip instance creation'!
+
+connectTo:service on:host
+ "standard setup: create new client tcp socket, bind and connect;
+ return the socket.
+ The system will 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:'nntp' on:(OperatingSystem getEnvironment:'NNTPSERVER')
+ "
+!
+
+provide:service
+ "standard 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:#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 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|
+
+ 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."
+
+ |newSock|
+
+ newSock := self newTCP.
+ newSock notNil ifTrue:[
+ (newSock connectTo:hostname port:(self portOfService:aService)) ifFalse:[
+ ^ nil
+ ]
+ ].
+ ^ newSock
+"
+same as:
+ ^ (self new) for:hostname port:(self portOfService:aPort).
+"
+ "
+
+ Socket newTCPclientToHost:'slsv6bt' port:'nntp'
+ "
+!
+
+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
+"
+!
+
+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
+"
! !
!Socket methodsFor:'socket setup'!
@@ -331,81 +508,85 @@
This is a low level entry; no binding, listening or connect
is done."
+ filePointer notNil ifTrue:[
+ ^ self error:'already created'
+ ].
%{
FILE *fp;
int dom, typ, proto, sock;
- char *domName, *typName;
extern errno;
- extern OBJ ErrorNumber;
extern int _immediateInterrupt;
int savInt;
- if (! (__isString(domainArg) || __isSymbol(domainArg))) {
- printf("bad domain\n");
+ if (! __isSymbol(domainArg)) {
+ fprintf(stderr, "bad domain\n");
RETURN ( nil );
}
- if (! (__isString(typeArg) || __isSymbol(typeArg))) {
- printf("bad type\n");
+ if (! __isSymbol(typeArg)) {
+ fprintf(stderr, "bad type\n");
RETURN ( nil );
}
- domName = (char *) _stringVal(domainArg);
- typName = (char *) _stringVal(typeArg);
/*
* get address-family
*/
#ifdef AF_UNIX
- if (strcmp(domName, "unix") == 0)
+ if (domainArg == @symbol(unix))
dom = AF_UNIX;
else
#endif
#ifdef AF_INET
- if (strcmp(domName, "inet") == 0)
+ if (domainArg == @symbol(inet))
dom = AF_INET;
else
#endif
#ifdef AF_NS
- if (strcmp(domName, "ns") == 0)
+ if (domainArg == @symbol(ns))
dom = AF_NS;
else
#endif
+#ifdef AF_DECnet
+ if (domainArg == @symbol(DECnet))
+ dom = AF_DECnet;
+ else
+#endif
#ifdef AF_APPLETALK
- if (strcmp(domName, "appletalk") == 0)
+ if (domainArg == @symbol(appletalk))
dom = AF_APPLETALK;
else
#endif
#ifdef AF_X25
- if (strcmp(domName, "x25") == 0)
+ if (domainArg == @symbol(x25))
dom = AF_X25;
else
#endif
{
- printf("unknown domain <%s>\n", domName);
+ fprintf(stderr, "unknown domain <%s>\n", _stringVal(domainArg));
RETURN ( nil );
}
#ifdef SOCK_STREAM
- if (strcmp(typName, "stream") == 0)
+ if (typeArg == @symbol(stream))
typ = SOCK_STREAM;
else
#endif
#ifdef SOCK_DGRAM
- if (strcmp(typName, "datagram") == 0)
+ if (typeArg == @symbol(datagram))
typ = SOCK_DGRAM;
else
#endif
#ifdef SOCK_RAW
- if (strcmp(typName, "raw") == 0)
+ if (typeArg == @symbol(raw))
typ = SOCK_RAW;
else
#endif
#ifdef SOCK_SEQPACKET
- if (strcmp(typName, "seqPacket") == 0)
+ if (typeArg == @symbol(seqPacket))
typ = SOCK_SEQPACKET;
else
#endif
{
- fprintf(stderr, "bad type <%s>\n", typName);
+ fprintf(stderr, "bad type <%s>\n", _stringVal(typeArg));
RETURN ( nil );
}
@@ -423,7 +604,7 @@
_INST(filePointer) = MKOBJ(fp);
}
} else
- ErrorNumber = _MKSMALLINT(errno);
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
%}
.
"all ok?"
@@ -436,8 +617,17 @@
!
for:hostName udpPort:portNr
- "setup for a UDP socket - if hostname is nil, a server port is opened;
- otherwise a client port to the server on host."
+ "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,"
+
+ filePointer notNil ifTrue:[
+ ^ self error:'already created'
+ ].
%{
struct sockaddr_in sa ;
struct hostent *hp ;
@@ -447,7 +637,6 @@
extern int _immediateInterrupt;
int savInt;
extern errno;
- extern OBJ ErrorNumber;
int ret;
if (! _isSmallInteger(portNr)) {
@@ -464,7 +653,7 @@
sa.sin_family = AF_INET ;
} else {
/*
- * is hostname -
+ * is hostname -
* do we know the host's address?
*/
if ((hp = gethostbyname((char *) _stringVal(hostName))) == NULL) {
@@ -488,7 +677,7 @@
if (sock < 0) {
printf("socket failed\n");
_immediateInterrupt = savInt;
- ErrorNumber = _MKSMALLINT(errno);
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
RETURN ( nil );
}
@@ -502,7 +691,7 @@
} while ((ret < 0) && (errno == EINTR));
if (ret < 0) {
printf("bind failed\n");
- }
+ }
} else {
sa.sin_port = htons((u_short) _intVal(portNr)) ;
do {
@@ -510,11 +699,11 @@
} while ((ret < 0) && (errno == EINTR));
if (ret < 0) {
printf("connect failed\n");
- }
+ }
}
_immediateInterrupt = savInt;
if (ret < 0) {
- ErrorNumber = _MKSMALLINT(errno);
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
close(sock) ;
RETURN ( nil );
}
@@ -545,8 +734,17 @@
!
for:hostName port:portNr
- "setup for a tcp socket. If hostname is nil, a server port is opened
- otherwise a client port to the server on host."
+ "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,"
+
+ filePointer notNil ifTrue:[
+ ^ self error:'already created'
+ ].
%{
struct sockaddr_in sa ;
struct hostent *hp ;
@@ -556,12 +754,11 @@
extern int _immediateInterrupt;
int savInt;
extern errno;
- extern OBJ ErrorNumber;
int ret;
int on = 1;
if (! _isSmallInteger(portNr)) {
- fprintf(stderr, "invalid port");
+ fprintf(stderr, "invalid port");
RETURN ( nil );
}
@@ -574,9 +771,8 @@
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 {
/*
* do we know the host's address?
@@ -598,10 +794,11 @@
do {
sock = socket(sa.sin_family, SOCK_STREAM, 0);
} while ((sock < 0) && (errno == EINTR));
+
if (sock < 0) {
printf("socket failed\n");
_immediateInterrupt = savInt;
- ErrorNumber = _MKSMALLINT(errno);
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
RETURN ( nil );
}
@@ -630,7 +827,7 @@
_immediateInterrupt = savInt;
if (ret < 0) {
- ErrorNumber = _MKSMALLINT(errno);
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
close(sock) ;
RETURN ( nil );
}
@@ -663,109 +860,268 @@
!Socket methodsFor:'low level'!
closeFile
- "low level close - may be redefined in subclasses"
+ "low level close"
%{ /* NOCONTEXT */
OBJ t;
- FILE *fp;
t = _INST(filePointer);
if (t != nil) {
- fp = MKFD(t);
+ FILE *fp;
+
+ fp = MKFD(t);
fflush(fp);
shutdown(fileno(fp), 2);
fclose(fp);
- _INST(filePointer) = nil;
+ _INST(filePointer) = nil;
}
%}
!
bindTo:portNumber address:address
+ "low level bind - returns true if ok, false otherwise.
+ (currently only non-address binding is supported; i.e. address
+ must be nil)"
+
+ filePointer isNil ifTrue:[
+ ^ self error:'not a valid socket'
+ ].
%{
- OBJ fp = _INST(filePointer);
- int fd;
- int family;
+ OBJ t = _INST(filePointer);
+ int sock;
struct sockaddr_in insock;
- int ok = 1;
- extern OBJ _inet;
int ret;
extern errno;
- extern OBJ ErrorNumber;
int on = 1;
+ int ok;
- if (_INST(domain) == _inet) {
+ if (!__isString(_INST(domain)) && !__isSymbol(_INST(domain))) {
+ fprintf(stderr, "invalid domain\n");
+ RETURN (false);
+ }
+
+ ok = 0;
+#ifdef AF_INET
+ if (_INST(domain) == @symbol(inet)) {
/*
- * INET addresses
+ * INET addresses - port must be a smallinteger
*/
insock.sin_family = AF_INET;
- if (_isSmallInteger(portNumber)) {
- insock.sin_port = htons(_intVal(portNumber));
- if (address == nil) {
- insock.sin_addr.s_addr = htonl(INADDR_ANY);
- } else
- ok = 0;
- } else
- ok = 0;
- } else
- ok = 0;
+ if (! _isSmallInteger(portNumber)) {
+ fprintf(stderr, "invalid port\n");
+ RETURN (false);
+ }
+ insock.sin_port = htons(_intVal(portNumber));
+ if (address == nil) {
+ insock.sin_addr.s_addr = htonl(INADDR_ANY);
+ ok = 1;
+ } else {
+ fprintf(stderr, "address bind not supported\n");
+ RETURN (false);
+ }
+ }
+#endif
+ /*
+ * XXXX add addressing stuff for other domains here ...
+ */
+#ifdef AF_UNIX
+ if (_INST(domain) == @symbol(unix)) {
+ }
+#endif
+#ifdef AF_X25
+ if (_INST(domain) == @symbol(x25)) {
+ }
+#endif
+#ifdef AF_NS
+ if (_INST(domain) == @symbol(ns)) {
+ }
+#endif
+#ifdef AF_APPLETALK
+ if (_INST(domain) == @symbol(appletalk)) {
+ }
+#endif
- if (ok) {
- if (fp != nil) {
- fd = fileno(MKFD(fp));
+ if (! ok) {
+ fprintf(stderr, "unsupported domain\n");
+ RETURN (false);
+ }
+
+ sock = fileno(MKFD(t));
+
#ifdef SO_REUSEADDR
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
- printf("setsockopt - SO_REUSEADDR failed\n");
- }
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
+ fprintf(stderr, "setsockopt - SO_REUSEADDR failed\n");
+ }
#endif /* SO_REUSEADDR */
- do {
- ret = bind(fd, (struct sockaddr *)&insock, sizeof(insock));
- } while ((ret < 0) && (errno == EINTR));
- if (ret < 0) {
- ErrorNumber = _MKSMALLINT(errno);
- RETURN ( false) ;
- }
- RETURN ( true );
- }
+
+ do {
+ ret = bind(sock, (struct sockaddr *)&insock, sizeof(insock));
+ } while ((ret < 0) && (errno == EINTR));
+
+ if (ret < 0) {
+ fprintf(stderr, "bind failed\n");
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
+ RETURN ( false) ;
}
%}
.
- ^ false
+ portNr := portNumber.
+ ^ true
- "(Socket domain:#inet type:#stream protocol:nil)
- bindTo:port
- address:nil"
+ "
+ (Socket domain:#inet type:#stream)
+ bindTo:9999
+ address:nil
+ "
!
-listenWithBacklog:aNumber
+connectTo:hostName port:aPortNr
+ "low level connect; connect to port, aPortNr on host, hostName.
+ Return true if ok, false otherwise."
+
+ filePointer isNil ifTrue:[
+ ^ self error:'not a valid socket'
+ ].
%{
- OBJ fp = _INST(filePointer);
- int fd;
+ OBJ t = _INST(filePointer);
+ struct sockaddr_in sa ;
+ struct hostent *hp ;
+ int a, sock ;
+ long addr;
+ FILE *fp;
extern int _immediateInterrupt;
int savInt;
extern errno;
- extern OBJ ErrorNumber;
+ int ret;
+ int on = 1;
+ int ok;
+
+ if (! __isString(hostName)) {
+ fprintf(stderr, "invalid hostname\n");
+ RETURN (false);
+ }
+ if (!__isString(_INST(domain)) && !__isSymbol(_INST(domain))) {
+ fprintf(stderr, "invalid domain\n");
+ RETURN (false);
+ }
+
+ ok = 0;
+#ifdef AF_INET
+ if (_INST(domain) == @symbol(inet)) {
+ if (! _isSmallInteger(aPortNr)) {
+ fprintf(stderr, "invalid port\n");
+ RETURN (false);
+ }
+
+ bzero((char *) &sa, sizeof(sa)) ;
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons((u_short) _intVal(aPortNr)) ;
+
+ if ((addr = inet_addr((char *) _stringVal(hostName))) != -1) {
+ /*
+ * is Internet addr in octet notation
+ */
+ bcopy(&addr, (char *) &sa.sin_addr, sizeof(addr)) ; /* set address */
+ ok = 1;
+ } else {
+ /*
+ * do we know the host's address?
+ */
+ if ((hp = gethostbyname((char *) _stringVal(hostName))) == NULL) {
+ fprintf(stderr, "unknown host:%s\n", _stringVal(hostName));
+ RETURN (false);
+ }
+ bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length) ;
+ sa.sin_family = hp->h_addrtype;
+ ok = 1;
+ }
+ }
+#endif
+ /*
+ * XXXX add addressing stuff for other domains here ...
+ */
+#ifdef AF_UNIX
+ if (_INST(domain) == @symbol(unix)) {
+ }
+#endif
+#ifdef AF_X25
+ if (_INST(domain) == @symbol(x25)) {
+ }
+#endif
+#ifdef AF_NS
+ if (_INST(domain) == @symbol(ns)) {
+ }
+#endif
+#ifdef AF_APPLETALK
+ if (_INST(domain) == @symbol(appletalk)) {
+ }
+#endif
+
+ if (! ok) {
+ fprintf(stderr, "unsupported domain\n");
+ RETURN (false);
+ }
+
+ sock = fileno(MKFD(t));
+
+ /*
+ * connect
+ */
+ savInt = _immediateInterrupt;
+ _immediateInterrupt = 1;
+
+ do {
+ ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa));
+ } while ((ret < 0) && (errno == EINTR));
+ _immediateInterrupt = savInt;
+
+ if (ret < 0) {
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
+ RETURN (false);
+ }
+%}
+.
+ portNr := aPortNr.
+ ^ true
+!
+
+listenWithBacklog:aNumber
+ "start listening; return true if ok, false on error"
+
+ filePointer isNil ifTrue:[
+ ^ self error:'not a valid socket'
+ ].
+%{
+ OBJ fp = _INST(filePointer);
+ int sock;
+ extern int _immediateInterrupt;
+ int savInt;
+ extern errno;
int ret;
- if (fp != nil) {
- fd = fileno(MKFD(fp));
- if (_isSmallInteger(aNumber)) {
- savInt = _immediateInterrupt;
- _immediateInterrupt = 1;
- do {
- ret = listen(fd, _intVal(aNumber));
- } while ((ret < 0) && (errno == EINTR));
- _immediateInterrupt = savInt;
- if (ret < 0) {
- ErrorNumber = _MKSMALLINT(errno);
- RETURN ( false) ;
- }
- RETURN (true );
- }
- }
+ if (! _isSmallInteger(aNumber)) {
+ fprintf(stderr, "invalid arg\n");
+ RETURN (false);
+ }
+
+ sock = fileno(MKFD(fp));
+
+ savInt = _immediateInterrupt;
+ _immediateInterrupt = 1;
+ do {
+ ret = listen(sock, _intVal(aNumber));
+ } while ((ret < 0) && (errno == EINTR));
+ _immediateInterrupt = savInt;
+
+ if (ret < 0) {
+ fprintf(stderr, "listen failed\n");
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
+ RETURN ( false) ;
+ }
%}
.
- ^ false
+ ^ true
!
listenFor:aNumber
@@ -777,20 +1133,29 @@
acceptOn:aSocket
"accept a connection on a server port (created with:'Socket>>onIPPort:')
usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)).
+ Return the receiver if ok; return nil if not.
NOTICE: this method will block, if no connection is already pending.
use readWait or Socket>>accept."
- |fileDes|
+ |serverSocketFd|
filePointer notNil ifTrue:[
- self error:'already connected'
+ ^ self error:'already connected'
].
- fileDes := aSocket fileDescriptor.
+ serverSocketFd := aSocket fileDescriptor.
+
+ serverSocketFd isNil ifTrue:[
+ ^ self error:'invalid server socket'
+ ].
+
+ domain := aSocket domain.
+ socketType := aSocket type.
+
%{
FILE *fp;
int flags;
- int fd, newFd;
+ int sock, newSock;
struct sockaddr_in sa ;
int alen;
struct hostent *he ;
@@ -798,52 +1163,60 @@
char dotted[20] ;
extern int _immediateInterrupt;
extern errno;
- extern OBJ ErrorNumber;
alen = sizeof(sa) ;
- if (! _isSmallInteger(fileDes)) {
+ if (! _isSmallInteger(serverSocketFd)) {
+ fprintf(stderr, "invalid fd\n");
+ RETURN (nil);
+ }
+
+ sock = _intVal(serverSocketFd);
+ flags = ioctl(sock, F_GETFL, 0);
+ ioctl(sock, F_SETFL, flags | O_NDELAY);
+ _immediateInterrupt = 1;
+ do {
+ newSock = accept(sock, (struct sockaddr *) &sa, &alen);
+ } while ((newSock < 0) && (errno == EINTR));
+ _immediateInterrupt = 0;
+
+ if (newSock < 0) {
+ fprintf(stderr, "accept failed\n");
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
RETURN (nil);
}
- fd = _intVal(fileDes);
- flags = ioctl(fd, F_GETFL, 0);
- ioctl(fd, F_SETFL, flags | O_NDELAY);
- _immediateInterrupt = 1;
- do {
- newFd = accept(fd, (struct sockaddr *) &sa, &alen);
- } while ((newFd < 0) && (errno == EINTR));
- _immediateInterrupt = 0;
-
- if (newFd < 0) {
- ErrorNumber = _MKSMALLINT(errno);
- RETURN (nil);
+ /*
+ * extract the partners address
+ */
+#ifdef AF_INET
+ if (_INST(domain) == @symbol(inet)) {
+ he = gethostbyaddr((char *) &sa.sin_addr.s_addr, alen, AF_INET) ;
+ if (! he) {
+ norder = htonl(sa.sin_addr.s_addr) ;
+ sprintf(dotted, "%d.%d.%d.%d",
+# if defined(SYSV3) || defined(LINUX) || defined(IRIS)
+ (norder >> 24) & 0xFF,
+ (norder >> 16) & 0xFF,
+ (norder >> 8) & 0xFF,
+ norder & 0xFF);
+# else
+ sa.sin_addr.s_net, sa.sin_addr.s_host,
+ sa.sin_addr.s_lh, sa.sin_addr.s_impno);
+# endif
+ }
+ fprintf(stderr, "accepted connection from host %s\n",
+ (he ? he->h_name : dotted)) ;
+ _INST(peerName) = _MKSTRING((he ? he->h_name : dotted) COMMA_CON);
}
-
- he = gethostbyaddr((char *) &sa.sin_addr.s_addr, alen, AF_INET) ;
- if (! he) {
- norder = htonl(sa.sin_addr.s_addr) ;
- sprintf(dotted, "%d.%d.%d.%d",
-#if defined(SYSV3) || defined(LINUX) || defined(IRIS)
- (norder >> 24) & 0xFF,
- (norder >> 16) & 0xFF,
- (norder >> 8) & 0xFF,
- norder & 0xFF);
-#else
- sa.sin_addr.s_net, sa.sin_addr.s_host,
- sa.sin_addr.s_lh, sa.sin_addr.s_impno);
#endif
- }
- fprintf(stderr, "accepted connection from host %s\n",
- (he ? he->h_name : dotted)) ;
- _INST(peerName) = _MKSTRING((he ? he->h_name : dotted) COMMA_CON);
/*
* make it a FILE *
*/
- fp = fdopen(newFd, "r+");
+ fp = fdopen(newSock, "r+");
if (! fp) {
- ErrorNumber = _MKSMALLINT(errno);
- close(newFd);
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
+ close(newSock);
RETURN (nil);
}
/*
@@ -856,7 +1229,8 @@
buffered := false.
"
mode := #readwrite.
- binary := false
+ binary := false.
+ portNr := aSocket portNumber.
!
accept
@@ -883,6 +1257,80 @@
partners host after an accept."
^ peerName
+!
+
+portNumber
+ "return the port number to which the socket is bound"
+
+ ^ portNr
+!
+
+domain
+ "return the sockets addressing domain (i.e. #inet, #x25, #appletalk)"
+
+ ^ domain
+!
+
+type
+ "return the sockets connection type (i.e. #datagram, #stream etc)"
+
+ ^ socketType
+! !
+
+!Socket methodsFor:'specials'!
+
+sendTimeout:seconds
+ "set the send timeout - for special applications only"
+
+ |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(MKFD(fp));
+ opt = _intVal(millis) / (1000 / HZ);
+ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&opt, sizeof(int));
+ RETURN(true);
+ }
+#endif
+%}
+.
+ ^ false
+!
+
+receiveTimeout:seconds
+ "set the send timeout - for special applications only"
+
+ |millis|
+
+ filePointer isNil ifTrue:[
+ ^ self error:'not a valid socket'
+ ].
+ millis := (seconds * 1000) rounded.
+%{
+#if defined(SO_RCVTIMEO) && defined(SOL_SOCKET) && defined(HZ)
+ if (_isSmallInteger(millis)) {
+ OBJ fp = _INST(filePointer);
+ int sock;
+ int opt;
+
+ sock = fileno(MKFD(fp));
+ opt = _intVal(millis) / (1000 / HZ);
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&opt, sizeof(int));
+ RETURN(true);
+ }
+#endif
+%}
+.
+ ^ false
! !
!Socket methodsFor:'datagram transmission'!
@@ -897,15 +1345,16 @@
OBJ oClass;
OBJ fp = _INST(filePointer);
int nInstVars, nInstBytes, objSize;
- int fd;
+ int sock;
struct sockaddr_in sa ;
int alen;
int n;
char *cp;
int flags = 0;
+ extern errno;
if (fp != nil) {
- fd = fileno((FILE *)(_intVal(fp)));
+ sock = fileno((FILE *)(_intVal(fp)));
oClass = _Class(aDataBuffer);
switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
@@ -923,22 +1372,27 @@
objSize = _Size(aDataBuffer) - nInstBytes;
cp = (char *)_InstPtr(aDataBuffer) + nInstBytes;
- if (anAddressBuffer == nil) {
- n = recvfrom(fd, cp, objSize, flags, (struct sockaddr *) 0, 0);
- } else {
- n = recvfrom(fd, cp, objSize, flags, (struct sockaddr *) &sa, &alen);
- oClass = _Class(anAddressBuffer);
- if ((_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) == BYTEARRAY) {
- nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
- nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
- objSize = _Size(anAddressBuffer) - nInstBytes;
- cp = (char *)_InstPtr(anAddressBuffer) + nInstBytes;
- if (objSize >= alen) {
- bcopy((char *)&sa, cp, alen);
- }
- }
- }
- RETURN (_MKSMALLINT(n));
+ if (anAddressBuffer == nil) {
+ n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) 0, 0);
+ } else {
+ n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) &sa, &alen);
+ if (n >= 0) {
+ oClass = _Class(anAddressBuffer);
+ if ((_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) == BYTEARRAY) {
+ nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
+ nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
+ objSize = _Size(anAddressBuffer) - nInstBytes;
+ cp = (char *)_InstPtr(anAddressBuffer) + nInstBytes;
+ if (objSize >= alen) {
+ bcopy((char *)&sa, cp, alen);
+ }
+ }
+ }
+ }
+ if (n < 0) {
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
+ }
+ RETURN (_MKSMALLINT(n));
}
bad: ;
%}
@@ -955,27 +1409,28 @@
OBJ oClass;
OBJ fp = _INST(filePointer);
int nInstVars, nInstBytes, objSize;
- int fd;
+ int sock;
struct sockaddr_in sa ;
int alen = sizeof(sa);
int n;
char *cp;
int flags = 0;
+ extern errno;
if (fp != nil) {
- fd = fileno((FILE *)(_intVal(fp)));
+ sock = fileno((FILE *)(_intVal(fp)));
- oClass = _Class(anAddressBuffer);
- if ((_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) == BYTEARRAY) {
- nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
- nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
- objSize = _Size(anAddressBuffer) - nInstBytes;
- cp = (char *)_InstPtr(anAddressBuffer) + nInstBytes;
- if (objSize <= alen) {
- bcopy(cp, (char *)&sa, objSize);
- alen = objSize;
- }
- }
+ oClass = _Class(anAddressBuffer);
+ if ((_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) == BYTEARRAY) {
+ nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars);
+ nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
+ objSize = _Size(anAddressBuffer) - nInstBytes;
+ cp = (char *)_InstPtr(anAddressBuffer) + nInstBytes;
+ if (objSize <= alen) {
+ bcopy(cp, (char *)&sa, objSize);
+ alen = objSize;
+ }
+ }
oClass = _Class(aDataBuffer);
switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
@@ -993,12 +1448,15 @@
objSize = _Size(aDataBuffer) - nInstBytes;
cp = (char *)_InstPtr(aDataBuffer) + nInstBytes;
- if (anAddressBuffer == nil) {
- n = sendto(fd, cp, objSize, flags, (struct sockaddr *) 0, 0);
- } else {
- n = sendto(fd, cp, objSize, flags, (struct sockaddr *) &sa, alen);
- }
- RETURN (_MKSMALLINT(n));
+ if (anAddressBuffer == nil) {
+ n = sendto(sock, cp, objSize, flags, (struct sockaddr *) 0, 0);
+ } else {
+ n = sendto(sock, cp, objSize, flags, (struct sockaddr *) &sa, alen);
+ }
+ if (n < 0) {
+ ExternalStream_LastErrorNumber = _MKSMALLINT(errno);
+ }
+ RETURN (_MKSMALLINT(n));
}
bad: ;
%}