--- a/UnixOperatingSystem.st Fri Dec 21 17:36:26 2001 +0100
+++ b/UnixOperatingSystem.st Fri Dec 21 17:42:00 2001 +0100
@@ -47,6 +47,13 @@
privateIn:UnixOperatingSystem
!
+UnixOperatingSystem::FileDescriptorHandle subclass:#SocketHandle
+ instanceVariableNames:''
+ classVariableNames:'ProtocolCache'
+ poolDictionaries:''
+ privateIn:UnixOperatingSystem
+!
+
!UnixOperatingSystem primitiveDefinitions!
%{
@@ -488,8 +495,551 @@
# endif
#endif
+
+/*
+ * Socket defines
+ */
+
+
+#if defined(transputer)
+# define NO_SOCKET
+#endif
+
+/*
+ * which protocols can we support ?
+ */
+#ifndef NO_SOCKET
+# define WANT__AF_INET
+#endif
+
+#define WANT__AF_UNIX
+
+#ifdef __VMS__
+# undef WANT__AF_UNIX
+# define WANT_AF_DECnet
+#endif
+
+
+#ifdef LINUX
+/* kludge to avoid some redefines ... */
+# define _ARPA_NAMESER_H
+# define _NETINET_TCP_H
+#endif
+
+#if !defined(NO_SOCKET)
+# if defined(IRIS) && !defined(IRIX5)
+ /* no socket.h on 4.0.5h ?!?!? */
+# ifndef AF_UNIX
+# define AF_UNIX 1
+# endif
+# ifndef AF_INET
+# define AF_INET 2
+# endif
+
+# ifndef SOCK_STREAM
+# define SOCK_STREAM 1
+# endif
+# ifndef SOCK_DGRAM
+# define SOCK_DGRAM 2
+# endif
+# ifndef SOCK_RAW
+# define SOCK_RAW 3
+# endif
+# else
+# include <sys/socket.h>
+# endif
+
+# ifdef NEXT3
+# include <netinet/in_systm.h>
+# endif
+#endif
+
+
+/*
+ * see what we want ...
+ */
+#ifdef WANT__AF_UNIX
+# ifdef AF_UNIX
+# ifndef PF_UNIX
+# define PF_UNIX AF_UNIX
+# endif
+# endif
+#else
+# undef AF_UNIX
+#endif
+
+#ifdef WANT__AF_INET
+# ifdef AF_INET
+# ifndef PF_INET
+# define PF_INET AF_INET
+# endif
+# endif
+#else
+# undef AF_INET
+#endif
+
+#ifdef WANT__AF_INET6
+# ifdef AF_INET6
+# ifndef PF_INET6
+# define PF_INET6 AF_INET6
+# endif
+# endif
+#else
+# undef AF_INET6
+#endif
+
+#ifdef WANT__AF_DECnet
+# ifdef AF_DECnet
+# ifndef PF_DECnet
+# define PF_DECnet AF_DECnet
+# endif
+# endif
+#else
+# undef AF_DECnet
+#endif
+
+#ifdef WANT__AF_APPLETALK
+# ifdef AF_APPLETALK
+# ifndef PF_APPLETALK
+# define PF_APPLETALK AF_APPLETALK
+# endif
+# endif
+#else
+# undef AF_APPLETALK
+#endif
+
+#ifdef WANT__AF_X25 /* X.25 */
+# ifdef AF_X25
+# ifndef PF_X25
+# define PF_X25 AF_X25
+# endif
+# endif
+#else
+# undef AF_X25
+#endif
+
+#ifdef WANT__AF_NS /* Xerox XNS */
+# ifdef AF_NS
+# ifndef PF_NS
+# define PF_NS AF_NS
+# endif
+# endif
+#else
+# undef AF_NS
+#endif
+
+#ifdef WANT__AF_SNA /* IBM SNA */
+# ifdef AF_SNA
+# ifndef PF_SNA
+# define PF_SNA AF_SNA
+# endif
+# endif
+#else
+# undef AF_SNA
+#endif
+
+#ifdef WANT__AF_RAW /* RAW packets */
+# ifdef AF_RAW
+# ifndef PF_RAW
+# define PF_RAW AF_RAW
+# endif
+# endif
+#else
+# undef AF_RAW
+#endif
+
+#ifdef WANT__AF_ISO /* ? */
+# ifdef AF_ISO
+# ifndef PF_ISO
+# define PF_ISO AF_ISO
+# endif
+# endif
+#else
+# undef AF_ISO
+#endif
+
+#ifdef WANT__AF_NETBIOS /* NETBIOS */
+# ifdef AF_NETBIOS
+# ifndef PF_NETBIOS
+# define PF_NETBIOS AF_NETBIOS
+# endif
+# endif
+#else
+# undef AF_NETBIOS
+#endif
+
+#ifdef WANT__AF_CCITT /* ? */
+# if defined(AF_CCITT) && (AF_CCITT != AF_X25)
+# ifndef PF_CCITT
+# define PF_CCITT AF_CCITT
+# endif
+# endif
+#else
+# undef AF_CCITT
+#endif
+
+#ifdef WANT__AF_IPX /* Novell IPX */
+# ifdef AF_IPX
+# ifndef PF_IPX
+# define PF_IPX AF_IPX
+# endif
+# endif
+#else
+# undef AF_IPX
+#endif
+
+#ifdef WANT__AF_AX25 /* Amateur Radio AX.25 */
+# ifdef AF_AX25
+# ifndef PF_AX25
+# define PF_AX25 AF_AX25
+# endif
+# endif
+#else
+# undef AF_AX25
+#endif
+
+#ifdef WANT__AF_NETROM /* Amateur Radio NET/ROM */
+# ifdef AF_NETROM
+# ifndef PF_NETROM
+# define PF_NETROM AF_NETROM
+# endif
+# endif
+#else
+# undef AF_NETROM
+#endif
+
+#ifdef WANT__AF_BRIDGE /* multiprotocol bridge */
+# ifdef AF_BRIDGE
+# ifndef PF_BRIDGE
+# define PF_BRIDGE AF_BRIDGE
+# endif
+# endif
+#else
+# undef AF_BRIDGE
+#endif
+
+#ifdef WANT__AF_BSC /* BISYNC 2780/3780 */
+# ifdef AF_BSC
+# ifndef PF_BSC
+# define PF_BSC AF_BSC
+# endif
+# endif
+#else
+# undef AF_BSC
+#endif
+
+#ifdef WANT__AF_ROSE /* Amateur Radio X.25 PLP */
+# ifdef AF_ROSE
+# ifndef PF_ROSE
+# define PF_ROSE AF_ROSE
+# endif
+# endif
+#else
+# undef AF_ROSE
+#endif
+
+#ifdef WANT__AF_ATM /* ATM Services */
+# ifdef AF_ATM
+# ifndef PF_ATM
+# define PF_ATM AF_ATM
+# endif
+# endif
+#else
+# undef AF_ATM
+#endif
+
+#ifdef WANT__AF_BAN /* BAN / VINES IP Services */
+# ifdef AF_BAN
+# ifndef PF_BAN
+# define PF_BAN AF_BAN
+# endif
+# endif
+#else
+# undef AF_BAN
+#endif
+
+#ifdef WANT__AF_VOICEVIEW /* VoiceView Services W95 only */
+# ifdef AF_VOICEVIEW
+# ifndef PF_VOICEVIEW
+# define PF_VOICEVIEW AF_VOICEVIEW
+# endif
+# endif
+#else
+# undef AF_VOICEVIEW
+#endif
+
+#ifdef WANT__AF_IRDA /* infrared */
+# ifdef AF_IRDA
+# ifndef PF_IRDA
+# define PF_IRDA AF_IRDA
+# endif
+# endif
+#else
+# undef AF_IRDA
+#endif
+
+
+/*
+ * now, include what we have to ...
+ * undef support, if no include file is present
+ * (or I dont know yet, where to find it)
+ */
+
+#ifdef AF_UNIX
+# ifdef UNIX
+# include <sys/un.h>
+# else
+# undef AF_UNIX
+# endif
+#endif
+
+#ifdef AF_INET
+# include <netdb.h>
+# if defined(PRE_SUSE_7_2)
+# if defined(LINUX) && defined(AF_INET6)
+# include <linux/in.h>
+# else
+# include <netinet/in.h>
+# endif
+# else
+# include <netinet/in.h>
+# endif
+# if !defined(LINUX)
+# if ! (defined(SYSV3) && defined(mc88k))
+# include <netinet/tcp.h>
+# endif
+# endif
+#endif
+
+#ifdef AF_INET6
+# if defined(LINUX) && defined(__GLIBC__)
+# if defined(PRE_SUSE_7_2)
+# include <linux/in6.h>
+# endif
+# else
+# undef AF_INET6
+# endif
+#endif
+
+#ifdef AF_APPLETALK
+# ifdef LINUX
+# include <asm/types.h>
+# include <linux/atalk.h>
+# else
+# undef AF_APPLETALK
+# endif
+#endif
+
+#ifdef AF_DECNET
+# ifdef solaris2_0
+# include <X11/dni8.h>
+# else
+# undef AF_DECNET
+# endif
+#endif
+
+#ifdef AF_X25
+# ifdef LINUX
+# include <linux/x25.h>
+# else
+# undef AF_X25
+# endif
+#endif
+
+#ifdef AF_AX25
+# ifdef LINUX
+# include <linux/ax25.h>
+# else
+# undef AF_AX25
+# endif
+#endif
+
+#ifdef AF_IPX
+# ifdef LINUX
+# include <linux/ipx.h>
+# else
+# ifdef WIN32
+# include <wsipx.h>
+# else
+# undef AF_IPX
+# endif
+# endif
+#endif
+
+#ifdef AF_NETBIOS
+# ifdef WIN32
+# include <wsnetbs.h>
+# else
+# undef AF_NETBIOS
+# endif
+#endif
+
+#ifdef AF_ATM
+# ifdef WIN32
+# include <ws2atm.h>
+# else
+# undef AF_ATM
+# endif
+#endif
+
+#ifdef AF_BAN
+# ifdef WIN32
+# include <wsvns.h>
+# else
+# undef AF_BAN
+# endif
+#endif
+
+#ifdef AF_VOICEVIEW
+# ifdef WIN32
+# include <wsvv.h>
+# else
+# undef AF_VOICEVIEW
+# endif
+#endif
+
+#ifdef AF_IRDA
+# ifdef LINUX
+# include <linux/irda.h>
+# else
+# undef AF_IRDA
+# endif
+#endif
+
+#undef AF_SNA /* not yet implemented */
+#undef AF_RAW /* not yet implemented */
+#undef AF_NETROM /* not yet implemented */
+#undef AF_BRIDGE /* not yet implemented */
+#undef AF_BSC /* not yet implemented */
+
+
+/*
+ * see what is leftOver
+ */
+union sockaddr_u {
+#ifdef AF_UNIX
+ struct sockaddr_un un;
+#endif
+#ifdef AF_INET
+ struct sockaddr_in in;
+#endif
+#ifdef AF_INET6
+ struct sockaddr_in6 in6;
+#endif
+#ifdef AF_APPLETALK
+ struct sockaddr_at at;
+#endif
+#ifdef AF_DECNET
+ struct sockaddr_dn dn;
+#endif
+#ifdef AF_X25
+ struct sockaddr_x25 x25;
+#endif
+#ifdef AF_AX25
+ struct sockaddr_ax25 ax25;
+#endif
+#ifdef AF_IPX
+ struct sockaddr_ipx ipx;
+#endif
+#ifdef AF_NETBIOS
+ struct sockaddr_nb nb;
+#endif
+#ifdef AF_ATM
+ struct sockaddr_atm atm;
+#endif
+#ifdef AF_BAN
+ struct sockaddr_vns vns;
+#endif
+#ifdef AF_VOICEVIEW
+ struct sockaddr_vv vv;
+#endif
+#ifdef AF_IRDA
+ struct sockaddr_irda irda;
+#endif
+};
+
+
+#if defined(TRY_AGAIN) || defined(HOST_NOT_FOUND)
+# define USE_H_ERRNO
+#endif
+
+#ifdef USE_H_ERRNO
+# ifndef h_errno
+ extern h_errno;
+# endif
+#endif
+
+/*
+ * gethostbyname seems to have trouble
+ * sometimes, if interrupted while a request
+ * is on its way the name server.
+ * (although specified in the man-page,
+ * a check on TRY_AGAIN fails on iris)
+ */
+#ifdef LINUX
+
+# define GETHOSTBYNAME(hp, name) \
+ hp = gethostbyname((char *) name);
+
+# define GETHOSTBYADDR(hp, addr, alen, af) \
+ hp = gethostbyaddr(addr, alen, af);
+
+#else
+
+# ifdef IRIX5_3
+# define GETHOSTBYNAME(hp, name) \
+ do { \
+ __BEGIN_INTERRUPTABLE__ \
+ hp = gethostbyname((char *) name); \
+ __END_INTERRUPTABLE__ \
+ } while ((hp == NULL) && \
+ ((h_errno == TRY_AGAIN) || (errno == ECONNREFUSED)));
+
+# define GETHOSTBYADDR(hp, addr, alen, af) \
+ do { \
+ __BEGIN_INTERRUPTABLE__ \
+ hp = gethostbyaddr(addr, alen, af); \
+ __END_INTERRUPTABLE__ \
+ } while ((hp == NULL) && \
+ ((h_errno == TRY_AGAIN) || (errno == ECONNREFUSED)));
+# else
+# ifdef USE_H_ERRNO
+# define GETHOSTBYNAME(hp, name) \
+ do { \
+ __BEGIN_INTERRUPTABLE__ \
+ hp = gethostbyname((char *) name); \
+ __END_INTERRUPTABLE__ \
+ } while ((hp == NULL) && (h_errno == TRY_AGAIN));
+
+# define GETHOSTBYADDR(hp, addr, alen, af) \
+ do { \
+ __BEGIN_INTERRUPTABLE__ \
+ hp = gethostbyaddr(addr, alen, af); \
+ __END_INTERRUPTABLE__ \
+ } while ((hp == NULL) && (h_errno == TRY_AGAIN));
+# else
+# define GETHOSTBYNAME(hp, name) \
+ __BEGIN_INTERRUPTABLE__ \
+ hp = gethostbyname((char *) name); \
+ __END_INTERRUPTABLE__
+
+# define GETHOSTBYADDR(hp, addr, alen, af) \
+ __BEGIN_INTERRUPTABLE__ \
+ hp = gethostbyaddr(addr, alen, af); \
+ __END_INTERRUPTABLE__
+# endif
+# endif
+#endif
+
+#ifdef DEBUG
+# define DBGPRINTF(x) { if (__debugging__) printf x; }
+# define DBGFPRINTF(x) { if (__debugging__) fprintf x; }
+#else
+# define DBGPRINTF(x) /* as nothing */
+# define DBGFPRINTF(x) /* as nothing */
+#endif
+
%}
-
! !
!UnixOperatingSystem primitiveFunctions!
@@ -7554,6 +8104,17 @@
"Modified: 22.4.1996 / 13:14:46 / cg"
! !
+!UnixOperatingSystem class methodsFor:'socket creation'!
+
+socketWithDomain:domainArg type:typeArg protocol:protocolArg
+ "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."
+
+ ^ SocketHandle new domain:domainArg type:typeArg protocol:protocolArg
+! !
+
!UnixOperatingSystem class methodsFor:'time and date'!
computeDatePartsOf:osTime for:aBlock
@@ -8639,22 +9200,20 @@
"return the number of bytes available for reading, without blocking."
%{
-#ifdef NOTDEF /* does not work ... */
/*
* if available, try FIONREAD first, which is usually done faster.
*/
# if defined(FIONREAD)
{
- int n;
-
- if (__isSmallInteger(fd)) {
- if (ioctl(__intVal(fd), FIONREAD, &n) >= 0) {
- RETURN (__MKINT(n));
- }
- }
+ int n;
+
+ if (__isSmallInteger(fd)) {
+ if (ioctl(__intVal(fd), FIONREAD, &n) >= 0) {
+ RETURN (__MKINT(n));
+ }
+ }
}
# endif /* FIONREAD */
-#endif
%}.
^ (self readCheck:fd) ifTrue:[1] ifFalse:[0]
!
@@ -8665,22 +9224,23 @@
This depends on a working select or FIONREAD to be provided by the OS."
%{
-#ifdef NOTDEF /* does not work ... */
/*
* if available, try FIONREAD first, which is usually done faster.
*/
-# if defined(FIONREAD)
- {
- int n;
-
- if (__isSmallInteger(fd)) {
- if (n = ioctl(__intVal(fd), FIONREAD)) {
- printf("FIONREAD returns %d\n", n);
- }
- }
+# ifdef FIONREAD
+ if (__isSmallInteger(fd)) {
+ int result = 0;
+
+ if (ioctl(__smallIntegerVal(fd), FIONREAD, &result) >= 0) {
+ printf("FIONREAD returns %d\n", result);
+ if (result > 0) {
+ RETURN(true);
+ } else {
+ RETURN(false);
+ }
+ }
}
# endif /* FIONREAD */
-#endif
%}.
^ super readCheck:fd
@@ -9268,77 +9828,6 @@
!UnixOperatingSystem::FileDescriptorHandle methodsFor:'misc functions'!
-canReadWithoutBlocking
- "return true, if data is available on a filedescriptor
- (i.e. read is possible without blocking).
- This depends on a working select or FIONREAD to be provided by the OS."
-
-%{
- /*
- * if available, try FIONREAD first, which is usually done faster.
- */
-# ifdef FIONREAD
- {
- int n;
-
- if (__isSmallInteger(__INST(fd))) {
- if (n = ioctl(__intVal(__INST(fd)), FIONREAD)) {
- printf("FIONREAD returns %d\n", n);
- }
- }
- }
-# endif /* FIONREAD */
-
-# ifdef __VMS__
-# ifdef DOES_NOT_WORK_YET
- {
- /*
- * do a sys$qio ..
- * fd here is suposed to be a channel nr.
- */
- struct IOSB iosb;
- int status;
- int channel;
- struct typahdask sensebuf;
-
- if (__isSmallInteger(fd)) {
- channel = __intVal(fd);
- status = SYS$QIO(0, /* efn */
- channel,
- IO$_SENSEMODE | IO$M_TYPEAHDCNT,
- &iosb,
- 0, /* ast */
- 0, /* ast arg */
- &sensebuf, /* data */
- sizeof(sensebuf), /* data size */
- 0, 0, 0, 0);
- if (status != SS$_NORMAL) {
- fprintf(stderr, "OS [info]: SYS$QIO failed on %d\n", channel);
- } else {
- fprintf(stderr, "sys$QIO -> %d\n", sensebuf.typcnt);
- }
- }
- }
-# endif
-# endif /* __VMS__ */
-%}.
-
- OperatingSystem supportsSelect ifFalse:[
- "/ mhmh - what should we do then ?
- "/ For now, return true as if data was present,
- "/ and let the thread fall into the read.
- "/ It will then (hopefully) be desceduled there and
- "/ effectively polling for input.
-
- ^ true
- ].
-
- ^ (OperatingSystem selectOnAnyReadable:(Array with:fd)
- writable:nil
- exception:nil
- withTimeOut:0) == fd
-!
-
seekTo:newPosition from:whence
"seek to newPosition
whence is one of: #begin #current #end.
@@ -9488,6 +9977,92 @@
!UnixOperatingSystem::FileDescriptorHandle methodsFor:'queries'!
+canReadWithoutBlocking
+ "return true, if data is available on a filedescriptor
+ (i.e. read is possible without blocking).
+ This depends on a working select or FIONREAD to be provided by the OS."
+
+%{
+ int fd;
+
+ if (__isSmallInteger(__INST(fd))) {
+ fd = __smallIntegerVal(__INST(fd));
+
+ /*
+ * if available, try FIONREAD first, which is usually done faster.
+ */
+# ifdef FIONREAD
+ {
+ int result = 0;
+
+ if (ioctl(fd, FIONREAD, &result) >= 0) {
+ RETURN(result > 0 ? true : false);
+ }
+ }
+# endif /* FIONREAD */
+
+# if defined(__VMS__) && defined(DOES_NOT_WORK_YET)
+ {
+ /*
+ * do a sys$qio ..
+ * fd here is suposed to be a channel nr.
+ */
+ struct IOSB iosb;
+ int status;
+ int channel;
+ struct typahdask sensebuf;
+
+ status = SYS$QIO(0, /* efn */
+ fd,
+ IO$_SENSEMODE | IO$M_TYPEAHDCNT,
+ &iosb,
+ 0, /* ast */
+ 0, /* ast arg */
+ &sensebuf, /* data */
+ sizeof(sensebuf), /* data size */
+ 0, 0, 0, 0);
+ if (status != SS$_NORMAL) {
+ fprintf(stderr, "OS [info]: SYS$QIO failed on %d\n", fd);
+ } else {
+ fprintf(stderr, "sys$QIO -> %d\n", sensebuf.typcnt);
+ }
+ }
+# endif /* __VMS__ */
+ }
+%}.
+
+ OperatingSystem supportsSelect ifFalse:[
+ "/ mhmh - what should we do then ?
+ "/ For now, return true as if data was present,
+ "/ and let the thread fall into the read.
+ "/ It will then (hopefully) be desceduled there and
+ "/ effectively polling for input.
+
+ ^ true
+ ].
+
+ ^ (OperatingSystem selectOnAnyReadable:(Array with:fd)
+ writable:nil
+ exception:nil
+ withTimeOut:0) == fd
+
+ "
+ |h n|
+ h := OperatingSystem openFileForRead:'/etc/hosts'.
+ n := h canReadWithoutBlocking.
+ h close.
+ n
+ "
+
+ "
+ |h n|
+ h := OperatingSystem openFileForRead:'/dev/ttyS0'.
+ n := h canReadWithoutBlocking.
+ h close.
+ n
+ "
+!
+
canWriteWithoutBlocking
"return true, if filedescriptor can be written without blocking"
@@ -9511,6 +10086,36 @@
a file or some other OS object"
^ fd notNil
+!
+
+numAvailableForRead
+ "return the number of bytes available for reading, without blocking."
+
+%{
+ /*
+ * if available, try FIONREAD first, which is usually done faster.
+ */
+# if defined(FIONREAD)
+ {
+ int n = 0;
+
+ if (__isSmallInteger(__INST(fd))) {
+ if (ioctl(__smallIntegerVal(__INST(fd)), FIONREAD, &n) >= 0) {
+ RETURN (__MKINT(n));
+ }
+ }
+ }
+# endif /* FIONREAD */
+%}.
+ ^ self canReadWithoutBlocking ifTrue:[1] ifFalse:[0]
+
+ "
+ |h n|
+ h := OperatingSystem openFileForRead:'/etc/hosts'.
+ n := h numAvailableForRead.
+ h close.
+ n
+ "
! !
!UnixOperatingSystem::FileDescriptorHandle methodsFor:'registering'!
@@ -9623,7 +10228,7 @@
!UnixOperatingSystem::FilePointerHandle class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.107 2001-12-19 13:58:03 stefan Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.108 2001-12-21 16:42:00 stefan Exp $'
! !
!UnixOperatingSystem::FilePointerHandle methodsFor:'release'!
@@ -9932,9 +10537,1286 @@
"Modified: 28.12.1995 / 14:13:41 / stefan"
! !
+!UnixOperatingSystem::SocketHandle class methodsFor:'constants'!
+
+domainCodeOf:aSymbolOrInteger
+
+ |domainCode|
+
+%{ /*NOCONTEXT*/
+ int code = -1;
+
+ if (__isSmallInteger(aSymbolOrInteger) || aSymbolOrInteger == nil) {
+ RETURN(aSymbolOrInteger);
+ }
+#ifdef AF_INET
+ else if (aSymbolOrInteger == @symbol(inet))
+ code = AF_INET;
+#endif
+#ifdef AF_INET6
+ else if (aSymbolOrInteger == @symbol(inet6))
+ code = AF_INET6;
+#endif
+#ifdef AF_UNIX
+ else if (aSymbolOrInteger == @symbol(unix))
+ code = AF_UNIX;
+#endif
+#ifdef AF_APPLETALK
+ else if (aSymbolOrInteger == @symbol(appletalk))
+ code = AF_APPLETALK;
+#endif
+
+ if (code > 0)
+ domainCode = __MKSMALLINT(code);
+%}.
+
+ ^ domainCode.
+
+ "
+ self domainCodeOf:#inet
+ self domainCodeOf:#unix
+ self domainCodeOf:#inet6
+ self domainCodeOf:#appletalk
+ "
+!
+
+domainSymbolOf:anInteger
+
+ |domainSymbol|
+
+%{ /*NOCONTEXT*/
+
+ if (__isSmallInteger(anInteger)) {
+ switch(__intVal(anInteger)) {
+#ifdef AF_INET
+ case AF_INET:
+ domainSymbol = @symbol(inet);
+ break;
+#endif
+#ifdef AF_INET6
+ case AF_INET6:
+ domainSymbol = @symbol(inet6);
+ break;
+#endif
+#ifdef AF_UNIX
+ case AF_UNIX:
+ domainSymbol = @symbol(unix);
+ break;
+#endif
+#ifdef AF_APPLETALK
+ case AF_APPLETALK:
+ domainSymbol = @symbol(appletalk);
+ break;
+#endif
+ }
+ }
+%}.
+
+ ^ domainSymbol.
+
+ "
+ self domainSymbolOf:(self domainCodeOf:#inet)
+ self domainSymbolOf:(self domainCodeOf:#inet6)
+ self domainSymbolOf:(self domainCodeOf:#unix)
+ self domainSymbolOf:(self domainCodeOf:#appletalk)
+ "
+!
+
+protocolCodeOf:aNameOrNumber
+ "convert a symbol to a numeric protocol code"
+
+ |protocolCode protocolSymbol|
+
+%{
+ if (__isSmallInteger(aNameOrNumber) || aNameOrNumber == nil) {
+ RETURN(aNameOrNumber);
+ }
+%}.
+
+ ProtocolCache notNil ifTrue:[
+ protocolCode := ProtocolCache at:aNameOrNumber asSymbol
+ ifAbsent:[].
+ protocolCode notNil ifTrue:[
+ ^ protocolCode.
+ ].
+ ].
+
+%{
+#ifndef NO_SOCKET
+ struct protoent *protoent = 0;
+
+ if (__isString(aNameOrNumber) || __isSymbol(aNameOrNumber)) {
+ protoent = getprotobyname((char *) __stringVal(aNameOrNumber));
+ if (protoent) {
+ protocolCode = __MKSMALLINT(protoent->p_proto);
+ protocolSymbol = __MKSYMBOL(protoent->p_name, 0);
+ }
+ }
+#endif /*NO_SOCKET*/
+%}.
+
+ protocolSymbol notNil ifTrue:[
+ ProtocolCache isNil ifTrue:[
+ ProtocolCache := IdentityDictionary new.
+ ].
+ "beware of polluting the protocol cache with aliases"
+ ProtocolCache at:protocolSymbol put:protocolCode.
+ ].
+ ^ protocolCode
+
+ "
+ self protocolCodeOf:#tcp
+ self protocolCodeOf:#udp
+ self protocolCodeOf:#raw
+ "
+!
+
+protocolSymbolOf:anInteger
+ "convert a numeric protocol code to a symbol"
+
+ |protocolSymbol|
+
+ ProtocolCache notNil ifTrue:[
+ protocolSymbol := ProtocolCache keyAtIdentityValue:anInteger
+ ifAbsent:[].
+ protocolSymbol notNil ifTrue:[
+ ^ protocolSymbol.
+ ].
+ ].
+
+%{
+#ifndef NO_SOCKET
+ struct protoent *protoent = 0;
+
+ if (__isSmallInteger(anInteger)) {
+ protoent = getprotobynumber(__intVal(anInteger));
+ if (protoent) {
+ protocolSymbol = __MKSYMBOL(protoent->p_name, 0);
+ }
+ }
+#endif /*NO_SOCKET*/
+%}.
+
+ protocolSymbol notNil ifTrue:[
+ ProtocolCache isNil ifTrue:[
+ ProtocolCache := IdentityDictionary new.
+ ].
+ ProtocolCache at:protocolSymbol put:anInteger.
+ ].
+ ^ protocolSymbol
+
+
+ "
+ self protocolSymbolOf:(self protocolCodeOf:#tcp)
+ self protocolSymbolOf:(self protocolCodeOf:#udp)
+ self protocolSymbolOf:(self protocolCodeOf:#icmp)
+ "
+!
+
+socketAddressSize:aSymbol
+ "answer the os specific size of a socket address for domain aSymbol"
+
+ |socketSize|
+
+%{ /*NOCONTEXT*/
+ int size = -1;
+
+#ifdef AF_INET
+ if (aSymbol == @symbol(inet))
+ size = sizeof(struct sockaddr_in);
+#endif
+#ifdef AF_INET6
+ else if (aSymbol == @symbol(inet6))
+ size = sizeof(struct sockaddr_in6);
+#endif
+#ifdef AF_UNIX
+ else if (aSymbol == @symbol(unix))
+ size = sizeof(struct sockaddr_un);
+#endif
+#ifdef AF_APPLETALK
+ else if (aSymbol == @symbol(appletalk))
+ size = sizeof(struct sockaddr_at);
+#endif
+
+ if (size > 0)
+ socketSize = __MKSMALLINT(size);
+%}.
+ ^ socketSize
+!
+
+socketTypeCodeOf:aSymbolOrInteger
+
+ |typeCode|
+
+%{ /*NOCONTEXT*/
+ int code = -1;
+
+ if (__isSmallInteger(aSymbolOrInteger) || aSymbolOrInteger == nil) {
+ RETURN(aSymbolOrInteger);
+ }
+#ifdef SOCK_STREAM
+ else if (aSymbolOrInteger == @symbol(stream))
+ code = SOCK_STREAM;
+#endif
+#ifdef SOCK_DGRAM
+ if (aSymbolOrInteger == @symbol(datagram))
+ code = SOCK_DGRAM;
+#endif
+#ifdef SOCK_RAW
+ if (aSymbolOrInteger == @symbol(raw))
+ code = SOCK_RAW;
+#endif
+
+ if (code > 0)
+ typeCode = __MKSMALLINT(code);
+%}.
+
+ ^ typeCode.
+
+ "
+ self socketTypeCodeOf:#stream
+ self socketTypeCodeOf:#datagram
+ self socketTypeCodeOf:#raw
+ "
+!
+
+socketTypeSymbolOf:anInteger
+
+ |socketTypeSymbol|
+
+%{ /*NOCONTEXT*/
+
+ if (__isSmallInteger(anInteger)) {
+ switch(__intVal(anInteger)) {
+#ifdef SOCK_STREAM
+ case SOCK_STREAM:
+ socketTypeSymbol = @symbol(stream);
+ break;
+#endif
+#ifdef SOCK_DGRAM
+ case SOCK_DGRAM:
+ socketTypeSymbol = @symbol(datagram);
+ break;
+#endif
+#ifdef SOCK_RAW
+ case SOCK_RAW:
+ socketTypeSymbol = @symbol(raw);
+ break;
+#endif
+ }
+ }
+%}.
+
+ ^ socketTypeSymbol.
+!
+
+supportedProtocolFamilies
+ "return a collection of supported protocol families.
+ This list specifies what the Socket class supports -
+ socket creation may still fail, if your system was built
+ without it."
+
+ |list|
+
+ list := OrderedCollection new.
+
+%{
+#ifdef AF_INET
+%}.
+ list add:#inet.
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_UNIX
+%}.
+ list add:#unix.
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_INET6
+%}.
+ list add:#inet6. "/ internet v6
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_APPLETALK
+%}.
+ list add:#appletalk. "/ appletalk
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_DECnet
+%}.
+ list add:#decnet. "/ dec net
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_NS
+%}.
+ list add:#xns. "/ Xerox XNS
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_X25
+%}.
+ list add:#x25. "/ X.25
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_SNA
+%}.
+ list add:#sna. "/ IBM SNA
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_RAW
+%}.
+ list add:#raw. "/ ?? RAW packets
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_ISO
+%}.
+ list add:#iso. "/ ??
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_NETBIOS
+%}.
+ list add:#netbios. "/ ??
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_IPX
+%}.
+ list add:#ipx. "/ Novell IPX
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_AX25
+%}.
+ list add:#ax25. "/ Amateur Radio AX.25
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_NETROM
+%}.
+ list add:#netrom. "/ Amateur Radio NET/ROM
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_BRIDGE
+%}.
+ list add:#bridge. "/ multiprotocol bridge
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_BSC
+%}.
+ list add:#bsc. "/ BISYNC 2780/3780
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_ROSE
+%}.
+ list add:#rose. "/ Amateur Radio X.25 PLP
+%{
+#endif
+%}.
+
+%{
+#ifdef AF_IRDA
+%}.
+ list add:#irda. "/ infrared
+%{
+#endif
+%}.
+
+
+ ^ list
+
+ "
+ self supportedProtocolFamilies
+ "
+! !
+
+!UnixOperatingSystem::SocketHandle class methodsFor:'initialization'!
+
+reinitialize
+ "clear the protocol cache, when the system has been restarted"
+
+ ProtocolCache := nil.
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'accepting'!
+
+acceptWithPeerAddressBuffer:peerOrNil
+ "accept a connection on a server port.
+ Returns a new SocketHandle or nil if the operation
+ would block.
+ If peerOrNil is set to a ByteArray, the socket address
+ of the connection peer is stored into it."
+
+ |error newFd|
+
+%{
+#ifndef NO_SOCKET
+ int sock, newSock;
+ struct sockaddr *sap;
+ int alen;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (peerOrNil != nil &&
+ (!__isNonNilObject(peerOrNil) ||
+ (__intVal(__ClassInstPtr(__qClass(peerOrNil))->c_flags) & ARRAYMASK) != BYTEARRAY)) {
+ error = @symbol(badArgument2);
+ goto err;
+ }
+
+ sock = __smallIntegerVal(__INST(fd));
+
+again:
+ if (peerOrNil == nil) {
+ alen = 0;
+ sap = 0;
+ } else {
+ alen = __byteArraySize(peerOrNil);
+ sap = (struct sockaddr *)__byteArrayVal(peerOrNil);
+ }
+ newSock = accept(sock, sap, &alen);
+ if (newSock < 0) {
+ switch (errno) {
+ case EINTR:
+ __HANDLE_INTERRUPTS__;
+ goto again;
+
+#ifdef EWOULDBLOCK
+ case EWOULDBLOCK:
+#else
+#if defined(EAGAIN)
+ case EAGAIN:
+#endif
+#endif
+ RETURN(nil);
+
+ default:
+ error = __mkSmallInteger(errno);
+ goto err;
+ }
+ }
+ newFd = __mkSmallInteger(newSock);
+
+err:;
+#endif /* not NO_SOCKET */
+%}.
+ error notNil ifTrue:[
+ self error:error.
+ ] ifFalse:[
+ ^ self class for:newFd
+ ]
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'binding'!
+
+bindTo:socketAddress
+ "low level bind -
+ Set the local address of the socket"
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ int sock;
+ int sockaddr_size;
+ int ret;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__isNonNilObject(socketAddress) ||
+ (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ sockaddr_size = __byteArraySize(socketAddress);
+ sock = __INST(fd);
+
+again:
+ ret = bind(sock, (struct sockaddr *)__byteArrayVal(socketAddress), sockaddr_size);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ __HANDLE_INTERRUPTS__;
+ goto again;
+ } else {
+ error = __mkSmallInteger(errno);
+ goto err;
+ }
+ }
+
+ err:;
+#endif /* NO_SOCKET */
+%}.
+ error notNil ifTrue:[
+ self error:error.
+ ].
+
+ "
+ (Socket domain:#inet type:#stream)
+ bindTo:(IPSocketAddress hostAddress:IPSocketAddress anyAddress port:9999)
+ reuseAddress:false ;
+ yourself
+ "
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'connecting'!
+
+cancelConnect
+ "cancel an asynchronous connect in progress"
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ int sock;
+ int ret;
+ struct sockaddr sockaddr = { AF_UNSPEC };
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ sock = __smallIntegerVal(__INST(fd));
+
+ /*
+ * (dis-) connect by connecting to AF_UNSPEC socket
+ */
+again:
+ ret = connect(sock, &sockaddr, sizeof(sockaddr));
+ if (ret < 0) {
+ switch(errno) {
+ case EINTR:
+# ifdef EAGAIN
+ case EAGAIN:
+# endif
+ __HANDLE_INTERRUPTS__;
+ goto again;
+
+ default:
+ error = __MKSMALLINT(errno);
+ break;
+ }
+ }
+
+err:;
+#endif /* NO_SOCKET */
+%}.
+!
+
+connectTo:socketAddress
+ "low level connect; connect to a socket address.
+ Return true if connection has been established,
+ false, when the connection has been initiated but not yet
+ completed. If an error occured, an OSError is raised"
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ int sock;
+ int ret;
+ int sockaddr_size;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__isNonNilObject(socketAddress) ||
+ (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ sock = __smallIntegerVal(__INST(fd));
+ sockaddr_size = __qSize(socketAddress);
+
+again:
+ ret = connect(sock, (struct sockaddr *)__byteArrayVal(socketAddress), sockaddr_size);
+ if (ret >= 0) {
+ RETURN(true)
+ }
+
+ switch(errno) {
+ case EINTR:
+# ifdef EAGAIN
+ case EAGAIN:
+# endif
+ __HANDLE_INTERRUPTS__;
+ goto again;
+
+#if defined(EINPROGRESS) || defined(EALREADY)
+# ifdef EINPROGRESS
+ case EINPROGRESS:
+# endif
+# ifdef EALREADY
+ case EALREADY:
+# endif
+ RETURN(false);
+#endif
+
+ default:
+ error = __MKSMALLINT(errno);
+ break;
+ }
+
+err:;
+#endif /* NO_SOCKET */
+%}.
+ error notNil ifTrue:[
+ self error:error.
+ ^ self
+ ].
+
+ "
+ Socket newTCP connectTo:(IPSocketAddress hostAddress:IPSocketAddress local port:7)
+ withTimeout:nil.
+ Socket newTCP connectTo:(IPSocketAddress hostAddress:IPSocketAddress local port:5768)
+ withTimeout:nil.
+ Socket newTCP connectTo:(IPSocketAddress hostAddress:#[1 2 3 4] port:7)
+ withTimeout:nil.
+ "
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'datagram transmission'!
+
+receiveFrom:socketAddress buffer:aDataBuffer start:startIndex for:nBytes flags:flags
+ "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.
+
+ The thread blocks until data arrives - you may want to wait before
+ receiving, using #readWait or #readWaitWithTimeout:."
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ OBJ oClass;
+ int nInstVars, nInstBytes, objSize;
+ int sock;
+ struct sockaddr *saPtr;
+ int alen0, alen;
+ int n;
+ char *cp;
+ int __flags, __startIndex, __nBytes;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__isSmallInteger(startIndex) ||
+ (__startIndex = __intVal(startIndex)-1) < 0) {
+ if (startIndex == nil) {
+ __startIndex = 0;
+ } else {
+ error = @symbol(badArgument3);
+ goto err;
+ }
+ }
+ if (__isSmallInteger(nBytes)) {
+ __nBytes = __intVal(nBytes);
+ } else if (nBytes == nil) {
+ __nBytes = -1;
+ } else {
+ error = @symbol(badArgument4);
+ goto err;
+ }
+ if (!__isInteger(flags)) {
+ error = @symbol(badArgument5);
+ goto err;
+ }
+ __flags = __longIntVal(flags);
+ sock = __smallIntegerVal(__INST(fd));
+
+ oClass = __Class(aDataBuffer);
+ switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
+ case BYTEARRAY:
+ case WORDARRAY:
+ case SWORDARRAY:
+ case LONGARRAY:
+ case SLONGARRAY:
+ case FLOATARRAY:
+ case DOUBLEARRAY:
+ break;
+ default:
+ error = @symbol(badArgument2);
+ goto err;
+ }
+
+ nInstVars = __intVal(_ClassInstPtr(oClass)->c_ninstvars);
+ nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
+ objSize = __qSize(aDataBuffer) - nInstBytes;
+ nInstBytes += __startIndex;
+ objSize -= __startIndex;
+
+ if (__nBytes >= 0 &&__nBytes < objSize) {
+ objSize = __nBytes;
+ }
+
+ if (socketAddress == nil) {
+ alen0 = 0;
+ } else {
+ if (!__isNonNilObject(socketAddress) ||
+ (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ alen0 = __byteArraySize(socketAddress);
+ }
+ saPtr = (struct sockaddr *)0;
+
+again:
+ alen = alen0;
+ if (alen)
+ saPtr = (struct sockaddr *)__byteArrayVal(socketAddress);
+ cp = (char *)__InstPtr(aDataBuffer) + nInstBytes;
+ n = recvfrom(sock, cp, objSize, __flags, saPtr, &alen);
+ if (n < 0) {
+ if (errno == EINTR) {
+ __HANDLE_INTERRUPTS__;
+ goto again;
+ } else {
+ error = __MKSMALLINT(errno);
+ goto err;
+ }
+ }
+ RETURN (__mkSmallInteger(n));
+#endif
+err: ;
+%}.
+ self error:error.
+ ^ -1
+!
+
+sendTo:socketAddress buffer:aDataBuffer start:startIndex for:maxBytes flags:flags
+ "send datagramm data - fetch address of destination host from
+ anAddressBuffer, data from aDataBuffer starting at startIndex,
+ sending count bytes.
+ SocketAddress must be an instance of SocketAddress
+ Return the number of bytes transmitted, or a negative number on error."
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ OBJ oClass;
+ int nInstVars, nInstBytes, objSize;
+ int sock;
+ int alen, n;
+ struct sockaddr *saPtr;
+ char *cp;
+ int __flags;
+ int offs, __startIndex, __maxBytes;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__isSmallInteger(startIndex) ||
+ (__startIndex = __intVal(startIndex)-1) < 0) {
+ if (startIndex == nil) {
+ __startIndex = 0;
+ } else {
+ error = @symbol(badArgument3);
+ goto err;
+ }
+ }
+ if (__isSmallInteger(maxBytes)) {
+ __maxBytes = __intVal(maxBytes);
+ } else if (maxBytes == nil) {
+ __maxBytes = -1;
+ } else {
+ error = @symbol(badArgument4);
+ goto err;
+ }
+ if (!__isInteger(flags)) {
+ error = @symbol(badArgument5);
+ goto err;
+ }
+ __flags = __longIntVal(flags);
+ sock = __smallIntegerVal(__INST(fd));
+
+ oClass = __Class(aDataBuffer);
+ switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) {
+ case BYTEARRAY:
+ offs = __startIndex;
+ break;
+ case WORDARRAY:
+ case SWORDARRAY:
+ offs = __startIndex * 2;
+ break;
+ case LONGARRAY:
+ case SLONGARRAY:
+ offs = __startIndex * 4;
+ break;
+ case LONGLONGARRAY:
+ case SLONGLONGARRAY:
+ offs = __startIndex * 8;
+# ifdef __NEED_LONGLONG_ALIGN
+ offs += 4;
+# endif
+ case FLOATARRAY:
+ offs = __startIndex * sizeof(float);
+ break;
+ case DOUBLEARRAY:
+ offs = __startIndex * sizeof(double);
+# ifdef __NEED_DOUBLE_ALIGN
+ offs += 4;
+# endif
+ break;
+ default:
+ error = @symbol(badArgument2);
+ goto err;
+ }
+
+ nInstVars = __smallIntegerVal(_ClassInstPtr(oClass)->c_ninstvars);
+ nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ);
+ objSize = __qSize(aDataBuffer) - nInstBytes - offs;
+
+ if (__maxBytes >= 0 && __maxBytes < objSize) {
+# ifdef DGRAM_DEBUG
+ printf("cut off ...\n");
+# endif
+ objSize = __maxBytes;
+ }
+
+ if (socketAddress == nil) {
+ alen = 0;
+ } else {
+ if (! __isByteArray(socketAddress)) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ alen = __byteArraySize(socketAddress);
+ }
+ saPtr = (struct sockaddr *)0;
+
+again:
+ if (alen)
+ saPtr = (struct sockaddr *)__byteArrayVal(socketAddress);
+ cp = (char *)__InstPtr(aDataBuffer) + nInstBytes + offs;
+ n = sendto(sock, cp, objSize, __flags, saPtr, alen);
+ if (n < 0) {
+ if (errno == EINTR) {
+ __HANDLE_INTERRUPTS__;
+ goto again;
+ } else {
+ error = __MKSMALLINT(errno);
+ goto err;
+ }
+ }
+ RETURN (__mkSmallInteger(n));
+#endif
+err: ;
+%}.
+ self error:error.
+ ^ -1
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'initializing'!
+
+domain:domainArg type:typeArg protocol:protocolArg
+ "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."
+
+ |error domainCode protocolNumber|
+
+ domainCode := self class domainCodeOf:domainArg.
+ protocolArg notNil ifTrue:[
+ protocolNumber := self class protocolCodeOf:protocolArg
+ ].
+
+%{
+#ifndef NO_SOCKET
+ int dom, typ, proto = 0, sock, ret;
+ int on = 1;
+
+ if (__INST(fd) != nil) {
+ error = @symbol(internalError);
+ goto err;
+ }
+ if (! __isSmallInteger(domainCode)) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ if (! __isSymbol(typeArg)) {
+ error = @symbol(badArgument2);
+ goto err;
+ }
+ if (protocolNumber != nil) {
+ if (!__isSmallInteger(protocolNumber)) {
+ error = @symbol(badArgument3);
+ goto err;
+ }
+ proto = __smallIntegerVal(protocolNumber);
+ }
+ dom = __smallIntegerVal(domainCode);
+
+ /*
+ * get socket-type and protocol-type
+ */
+
+#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
+ {
+ error = @symbol(badArgument2);
+ goto err;
+ }
+
+againSocket:
+ sock = socket(dom, typ, proto);
+ if (sock < 0) {
+ if (errno == EINTR) {
+ __HANDLE_INTERRUPTS__;
+ goto againSocket;
+ } else
+#if defined(EPROTONOSUPPORT) /* for SGI */
+ if (errno == EPROTONOSUPPORT && proto != 0) {
+ proto = 0;
+ goto againSocket;
+ } else
+#endif
+ {
+ error = __mkSmallInteger(errno);
+ goto err;
+ }
+ }
+ __INST(fd) = __mkSmallInteger(sock);
+
+err:;
+#else
+ error := @symbol(notImplemented);
+#endif
+%}.
+ error notNil ifTrue:[
+ ^ self error:error.
+ ].
+ self register.
+
+ "
+ self new domain:#inet type:#stream protocol:nil
+ "
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'misc'!
+
+getOptionsLevel:level name:name
+ "answer a ByteArray containing the socket option value
+ named name at level"
+
+ |error bytes size|
+
+ bytes := ByteArray new:256.
+
+%{
+#ifndef NO_SOCKET
+ int sock;
+ int intval, sz;
+ char *p;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__bothSmallInteger(level, name)) {
+ error = @symbol(badArgument);
+ goto err;
+ }
+ if (!__isByteArray(bytes)) {
+ error = @symbol(internalError);
+ goto err;
+ }
+ p = __byteArrayVal(bytes);
+ sz = __byteArraySize(bytes);
+
+ sock = __smallIntegerVal(__INST(fd));
+ if (getsockopt(sock, __smallIntegerVal(level), __smallIntegerVal(name), p, &sz) < 0) {
+ error = __mkSmallInteger(errno);
+ }
+ size = __mkSmallInteger(sz);
+
+err:;
+#endif
+%}.
+ error notNil ifTrue:[
+ ^ self error:error
+ ].
+ ^ bytes copyTo:size
+!
+
+listenFor:aNumber
+ "start listening.
+ aNumber is the number of connect indications queues
+ by the operating system"
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ int sock, ret;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__isSmallInteger(aNumber)) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+
+ sock = __smallIntegerVal(__INST(fd));
+
+again:
+ ret = listen(sock, __smallIntegerVal(aNumber));
+ if (ret < 0) {
+ if (errno == EINTR) {
+ __HANDLE_INTERRUPTS__;
+ goto again;
+ } else {
+ error = __mkSmallInteger(errno);
+ }
+ }
+
+err:;
+#endif
+%}.
+ error notNil ifTrue:[
+ self error:error.
+ ].
+!
+
+setOptionsLevel:level name:name value:value
+ "set the socket option name at level to value.
+ Value ay be one of SmallInteger, ByteArray or nil"
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ int sock;
+ int intval, sz;
+ char *p;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__bothSmallInteger(level, name)) {
+ error = @symbol(badArgument);
+ goto err;
+ }
+ if (__isSmallInteger(value)) {
+ intval = __intVal(value);
+ p = (char *) &intval;
+ sz = sizeof(intval);
+ } else if (__isByteArray(value)) {
+ p = __byteArrayVal(value);
+ sz = __byteArraySize(value);
+ } else {
+ error = @symbol(badArgument3);
+ goto err;
+ }
+
+ sock = __smallIntegerVal(__INST(fd));
+ if (setsockopt(sock, __smallIntegerVal(level), __smallIntegerVal(name), p, sz) < 0) {
+ error = __mkSmallInteger(errno);
+ }
+err:;
+#endif
+%}.
+ error notNil ifTrue:[
+ ^ self error:error
+ ]
+!
+
+shutdown:anInteger
+ "inform the socket that no more I/O will happen.
+ anInteger == 0 no reads will be performed
+ anInteger == 1 no writes will be performed
+ anInteger == 2 neither reads nor writes will be performed.
+ Pending data is discarded. This is faster tha
+ close, which may wait until pending (written)
+ data has been read by the other side"
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ int ret;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__isSmallInteger(anInteger)) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+
+again:
+ ret = shutdown(__smallIntegerVal(__INST(fd)), __smallIntegerVal(anInteger));
+ if (ret < 0) {
+ if (errno == EINTR) {
+ __HANDLE_INTERRUPTS__;
+ goto again;
+ } else {
+ error = __mkSmallInteger(errno);
+ }
+ }
+
+err:;
+#endif /*NO_SOCKET*/
+%}.
+ error notNil ifTrue:[
+ self error:error
+ ]
+! !
+
+!UnixOperatingSystem::SocketHandle methodsFor:'queries'!
+
+getNameInto:socketAddress
+ "answer the my own address (I am bound to this address).
+ Note that this address may change after connect or accept."
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ int sock;
+ int sockaddr_size;
+ int ret;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__isNonNilObject(socketAddress) ||
+ (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ sockaddr_size = __byteArraySize(socketAddress);
+
+ sock = __smallIntegerVal(__INST(fd));
+ ret = getsockname(sock, (struct sockaddr *)__byteArrayVal(socketAddress), &sockaddr_size);
+ if (ret < 0) {
+ error = __MKSMALLINT(errno);
+ }
+err:;
+#endif /* NO_SOCKET */
+%}.
+ error notNil ifTrue:[
+ ^ self error:error
+ ].
+ ^ socketAddress
+!
+
+getPeerInto:socketAddress
+ "answer the my own address (I am bound to this address).
+ Note that this address may change after connect or accept."
+
+ |error|
+
+%{
+#ifndef NO_SOCKET
+ int sock;
+ int sockaddr_size;
+ int ret;
+
+ if (!__isSmallInteger(__INST(fd))) {
+ error = @symbol(badFd);
+ goto err;
+ }
+ if (!__isNonNilObject(socketAddress) ||
+ (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ sockaddr_size = __byteArraySize(socketAddress);
+
+ sock = __smallIntegerVal(__INST(fd));
+ ret = getpeername(sock, (struct sockaddr *)__byteArrayVal(socketAddress), &sockaddr_size);
+ if (ret < 0) {
+ error = __mkSmallInteger(errno);
+ }
+err:;
+#endif /* NO_SOCKET */
+%}.
+ error notNil ifTrue:[
+ ^ self error:error
+ ].
+ ^ socketAddress
+! !
+
!UnixOperatingSystem class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.107 2001-12-19 13:58:03 stefan Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.108 2001-12-21 16:42:00 stefan Exp $'
! !
UnixOperatingSystem initialize!