--- a/UnixOperatingSystem.st Wed Mar 26 14:14:53 2003 +0100
+++ b/UnixOperatingSystem.st Thu Mar 27 14:28:00 2003 +0100
@@ -8468,6 +8468,11 @@
!UnixOperatingSystem class methodsFor:'socket creation'!
+socketAccessor
+
+ ^ SocketHandle
+!
+
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
@@ -11173,23 +11178,23 @@
int code = -1;
if (__isSmallInteger(aSymbolOrInteger) || aSymbolOrInteger == nil) {
- RETURN(aSymbolOrInteger);
+ RETURN(aSymbolOrInteger);
}
#ifdef SOCK_STREAM
else if (aSymbolOrInteger == @symbol(stream))
- code = SOCK_STREAM;
+ code = SOCK_STREAM;
#endif
#ifdef SOCK_DGRAM
- if (aSymbolOrInteger == @symbol(datagram))
- code = SOCK_DGRAM;
+ else if (aSymbolOrInteger == @symbol(datagram))
+ code = SOCK_DGRAM;
#endif
#ifdef SOCK_RAW
- if (aSymbolOrInteger == @symbol(raw))
- code = SOCK_RAW;
+ else if (aSymbolOrInteger == @symbol(raw))
+ code = SOCK_RAW;
#endif
if (code > 0)
- typeCode = __MKSMALLINT(code);
+ typeCode = __MKSMALLINT(code);
%}.
^ typeCode.
@@ -11401,6 +11406,530 @@
ProtocolCache := nil.
! !
+!UnixOperatingSystem::SocketHandle class methodsFor:'queries'!
+
+getAddressInfo:hostName serviceName:serviceName domain:domainArg type:typeArg protocol:protoArg flags:flags
+ "answer an Array of socket addresses for serviceName on hostName
+ Domain, type, protocol may be nil or specify a hint for the socket
+ addresses to be returned."
+
+ |error errorString result domain type proto|
+
+ domain := self domainCodeOf:domainArg.
+ type := self socketTypeCodeOf:typeArg.
+ proto := self protocolCodeOf:protoArg.
+
+%{ /* STACK:32000 */
+/* #undef NI_NUMERICHOST */ /* undef to test gethost...() path */
+
+
+#if !defined(NO_SOCKET)
+ char *__hostName, *__serviceName;
+ int ret, cnt = 0;
+
+ if (hostName == nil) {
+ __hostName = 0;
+ } else if (__isString(hostName) || __isSymbol(hostName)) {
+ __hostName = __stringVal(hostName);
+ } else {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ if (serviceName == nil) {
+ __serviceName = 0;
+ } else if (__isString(serviceName) || __isSymbol(serviceName)) {
+ __serviceName = __stringVal(serviceName);
+ } else {
+ error = @symbol(badArgument2);
+ goto err;
+ }
+ if (__hostName == 0 && __serviceName == 0) {
+ error = @symbol(badArgument);
+ goto err;
+ }
+
+{
+# if defined(AI_NUMERICHOST)
+ struct addrinfo hints;
+ struct addrinfo *info = 0, *infop;
+
+ memset(&hints, 0, sizeof(hints));
+ if (__isSmallInteger(domain))
+ hints.ai_family = __intVal(domain);
+ if (__isSmallInteger(type))
+ hints.ai_socktype = __intVal(type);
+ if (__isSmallInteger(proto))
+ hints.ai_protocol = __intVal(proto);
+
+ do {
+ __BEGIN_INTERRUPTABLE__
+ ret = getaddrinfo(__hostName, __serviceName, &hints, &info);
+ __END_INTERRUPTABLE__
+ } while (ret == EAI_SYSTEM && errno == EINTR);
+ if (ret != 0) {
+ switch (ret) {
+ case EAI_FAMILY:
+ error = @symbol(badProtocol);
+ break;
+ case EAI_SOCKTYPE:
+ error = @symbol(badSocketType);
+ break;
+ case EAI_BADFLAGS:
+ error = @symbol(badFlags);
+ break;
+ case EAI_NONAME:
+ error = @symbol(unknownHost);
+ break;
+ case EAI_SERVICE:
+ error = @symbol(unknownService);
+ break;
+ case EAI_ADDRFAMILY :
+ error = @symbol(unknownHostForProtocol);
+ break;
+ case EAI_NODATA:
+ error = @symbol(noAddress);
+ break;
+ case EAI_MEMORY:
+ error = @symbol(allocationFailure);
+ break;
+ case EAI_FAIL:
+ error = @symbol(permanentFailure);
+ break;
+ case EAI_AGAIN:
+ error = @symbol(tryAgain);
+ break;
+ case EAI_SYSTEM:
+ error = @symbol(systemError);
+ break;
+ default:
+ error = @symbol(unknownError);
+ }
+ errorString = __MKSTRING(gai_strerror(ret));
+ goto err;
+ }
+ for (cnt=0, infop=info; infop; infop=infop->ai_next)
+ cnt++;
+
+ result = __ARRAY_NEW_INT(cnt);
+ if (result == nil) {
+ error = @symbol(allocationFailure);
+ goto err;
+ }
+ for (infop=info, cnt=0; infop; infop=infop->ai_next, cnt++) {
+ OBJ o, resp;
+
+ resp = __ARRAY_NEW_INT(6);
+ if (resp == nil) {
+ error = @symbol(allocationFailure);
+ goto err;
+ }
+
+ __ArrayInstPtr(result)->a_element[cnt] = resp;
+ __STORE(result, resp);
+ __ArrayInstPtr(resp)->a_element[0] = __MKSMALLINT(infop->ai_flags);
+ __ArrayInstPtr(resp)->a_element[1] = __MKSMALLINT(infop->ai_family);
+ __ArrayInstPtr(resp)->a_element[2] = __MKSMALLINT(infop->ai_socktype);
+ __ArrayInstPtr(resp)->a_element[3] = __MKSMALLINT(infop->ai_protocol);
+ o = __BYTEARRAY_NEW_INT(infop->ai_addrlen);
+ if (o == nil) {
+ error = @symbol(allocationFailure);
+ goto err;
+ }
+ memcpy(__byteArrayVal(o), infop->ai_addr, infop->ai_addrlen);
+ __ArrayInstPtr(resp)->a_element[4] = o;
+ __STORE(resp, o);
+ if (infop->ai_canonname) {
+ o = __MKSTRING(infop->ai_canonname);
+ if (o == nil) {
+ error = @symbol(allocationFailure);
+ goto err;
+ }
+ __ArrayInstPtr(resp)->a_element[5] = o;
+ __STORE(resp, o);
+ }
+ }
+
+err:
+ if (info) freeaddrinfo(info);
+
+# else /* ! AI_NUMERICHOST =============================================================*/
+
+ struct hostent *hp;
+ char **addrpp;
+ int port = 0;
+ int i;
+
+ /*
+ * Use gethostByName()
+ */
+
+ if (__serviceName) {
+ struct servent *sp;
+ char *__proto = 0;
+
+ if (__isString(protoArg) || __isSymbol(protoArg))
+ __proto = __stringVal(protoArg);
+
+ sp = getservbyname(__serviceName, __proto);
+ if (sp == NULL) {
+ errorString = @symbol(unknownService);
+ error = __mkSmallInteger(-3);
+ goto err;
+ }
+ port = sp->s_port;
+ }
+
+ if (__hostName) {
+# ifdef USE_H_ERRNO
+ do {
+ /* __BEGIN_INTERRUPTABLE__ is dangerous, because gethostbyname
+ * uses a static data area
+ */
+ __BEGIN_INTERRUPTABLE__
+ hp = gethostbyname(__hostName);
+ __END_INTERRUPTABLE__
+ } while ((hp == NULL)
+ && (
+ (h_errno == TRY_AGAIN)
+ || errno == EINTR
+# ifdef IRIX5_3
+ || (errno == ECONNREFUSED)
+# endif
+ )
+ );
+ if (hp == 0) {
+ switch (h_errno) {
+ case HOST_NOT_FOUND:
+ error = @symbol(unknownHost);
+ break;
+ case NO_ADDRESS:
+ error = @symbol(noAddress);
+ break;
+ case NO_RECOVERY:
+ error = @symbol(permanentFailure);
+ break;
+ case TRY_AGAIN:
+ error = @symbol(tryAgain);
+ break;
+ default:
+ error = @symbol(unknownError);
+ }
+ errorString = __MKSTRING(hstrerror(h_errno));
+ goto err;
+ }
+# else /* !USE_H_ERRNO */
+ hp = gethostbyname(__hostName);
+ if (hp == 0) {
+ errorString = @symbol(unknownHost);
+ error = __mkSmallInteger(-1);
+ goto err;
+ }
+# endif /* !USE_H_ERRNO*/
+
+ if (__isSmallInteger(domain) && hp->h_addrtype != __smallIntegerVal(domain)) {
+ errorString = @symbol(unknownHost);
+ error = __mkSmallInteger(-2);
+ goto err;
+ }
+
+ for (cnt = 0, addrpp = hp->h_addr_list; *addrpp; addrpp++)
+ cnt++;
+ addrpp = hp->h_addr_list;
+ } else {
+ cnt = 1;
+ }
+
+ result = __ARRAY_NEW_INT(cnt);
+ if (result == nil) {
+ error = @symbol(allocationFailure);
+ goto err;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ OBJ o, resp;
+ struct sockaddr_in *sa;
+
+ resp = __ARRAY_NEW_INT(6);
+ if (resp == nil) {
+ error = @symbol(allocationFailure);
+ goto err;
+ }
+
+ __ArrayInstPtr(result)->a_element[i] = resp;
+ __STORE(result, resp);
+ __ArrayInstPtr(resp)->a_element[0] = __mkSmallInteger(0);
+ __ArrayInstPtr(resp)->a_element[2] = type;
+ __ArrayInstPtr(resp)->a_element[3] = proto;
+ o = __BYTEARRAY_NEW_INT(sizeof(*sa));
+ if (o == nil) {
+ error = @symbol(allocationFailure);
+ goto err;
+ }
+ __ArrayInstPtr(resp)->a_element[4] = o;
+ __STORE(resp, o);
+ sa = (struct sockaddr_in *)__byteArrayVal(o);
+ sa->sin_port = port;
+
+ if (__hostName) {
+ sa->sin_family = hp->h_addrtype;
+ memcpy(&sa->sin_addr, *addrpp, hp->h_length);
+ __ArrayInstPtr(resp)->a_element[1] = __mkSmallInteger(hp->h_addrtype);
+ if (hp->h_name) {
+ o = __MKSTRING(hp->h_name);
+ if (o == nil) {
+ error = @symbol(allocationFailure);
+ goto err;
+ }
+ __ArrayInstPtr(resp)->a_element[5] = o;
+ __STORE(resp, o);
+ }
+ addrpp++;
+ } else{
+ __ArrayInstPtr(resp)->a_element[1] = domain;
+ }
+ }
+
+err:;
+# endif /* ! AI_NUMERICHOST */
+}
+#else /* ! HAS_SOCKET */
+ error = @symbol(notImplemented);
+#endif
+%}.
+ error notNil ifTrue:[
+ NameLookupError raiseWith:error errorString:errorString.
+ ].
+ 1 to:result size do:[:i |
+ |entry dom info|
+
+ info := SocketAddressInfo new.
+ entry := result at:i.
+ info flags:(entry at:1).
+ info domain:(dom := self domainSymbolOf:(entry at:2)).
+ info type:(self socketTypeSymbolOf:(entry at:3)).
+ info protocol:(self protocolSymbolOf:(entry at:4)).
+ info socketAddress:((SocketAddress newDomain:dom) fromBytes:(entry at:5)).
+ info canonicalName:(entry at:6).
+ result at:i put:info
+ ].
+ ^ result
+
+ "
+ self getAddressInfo:'localhost' serviceName:nil
+ domain:nil type:nil protocol:nil flags:nil
+ self getAddressInfo:'localhost' serviceName:nil
+ domain:#inet type:#stream protocol:nil flags:nil
+ self getAddressInfo:'localhost' serviceName:nil
+ domain:#inet type:#stream protocol:#tcp flags:nil
+ self getAddressInfo:'blurb.exept.de' serviceName:nil
+ domain:#inet type:nil protocol:nil flags:nil
+ self getAddressInfo:'1.2.3.4' serviceName:'bla'
+ domain:#inet type:nil protocol:nil flags:nil
+ self getAddressInfo:'localhost' serviceName:'echo'
+ domain:#inet type:nil protocol:nil flags:nil
+ self getAddressInfo:nil serviceName:'echo'
+ domain:#inet type:nil protocol:nil flags:nil
+ self getAddressInfo:nil serviceName:nil
+ domain:#inet type:nil protocol:nil flags:nil
+ "
+!
+
+getNameInfo:socketAddress wantHostName:wantHostName wantServiceName:wantServiceName datagram:useDatagram flags:flags
+ "answer an Array containing the hostName and serviceName
+ in socketAddress. SocketType may be one "
+
+ |error errorString hostName serviceName|
+
+%{ /* STACK:32000 */
+
+/* #undef NI_NUMERICHOST */ /* undef to test gethost...() path */
+
+#if !defined(NO_SOCKET)
+
+# ifndef NI_MAXHOST
+# define NI_MAXHOST 256
+# define NI_MAXSERV 64
+# endif
+
+ char host[NI_MAXHOST];
+ char service[NI_MAXSERV];
+ char *hp = 0, *sp = 0;
+ int hsz = 0, ssz = 0;
+ int ret, __flags;
+
+ if (wantHostName == true) {
+ hp = host;
+ hsz = sizeof(host);
+ }
+ if (wantServiceName == true) {
+ sp = service;
+ ssz = sizeof(service);
+ }
+ if (hp == 0 && sp == 0) {
+ error = @symbol(badArgument);
+ goto err;
+ }
+ if (!__isNonNilObject(socketAddress) ||
+ (__intVal(__ClassInstPtr(__qClass(socketAddress))->c_flags) & ARRAYMASK) != BYTEARRAY) {
+ DBGPRINTF(("SOCKET: bad socket address"));
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ if (!__isSmallInteger(flags)) {
+ error = @symbol(badArgument5);
+ goto err;
+ }
+ __flags = __intVal(flags);
+
+#if defined(NI_NUMERICHOST)
+ if (useDatagram == true) {
+ __flags |= NI_DGRAM;
+ }
+
+ {
+ __BEGIN_INTERRUPTABLE__
+ ret = getnameinfo((struct sockaddr *)__byteArrayVal(socketAddress),
+ __byteArraySize(socketAddress),
+ hp, hsz, sp, ssz, __flags);
+ __END_INTERRUPTABLE__
+ } while (ret == EAI_SYSTEM && errno == EINTR);
+ if (ret != 0) {
+ switch (ret) {
+ case EAI_FAMILY:
+ error = @symbol(badProtocol);
+ break;
+ case EAI_SOCKTYPE:
+ error = @symbol(badSocketType);
+ break;
+ case EAI_BADFLAGS:
+ error = @symbol(badFlags);
+ break;
+ case EAI_NONAME:
+ error = @symbol(unknownHost);
+ break;
+ case EAI_SERVICE:
+ error = @symbol(unknownService);
+ break;
+ case EAI_ADDRFAMILY :
+ error = @symbol(unknownHostForProtocol);
+ break;
+ case EAI_NODATA:
+ error = @symbol(noAddress);
+ break;
+ case EAI_MEMORY:
+ error = @symbol(allocationFailure);
+ break;
+ case EAI_FAIL:
+ error = @symbol(permanentFailure);
+ break;
+ case EAI_AGAIN:
+ error = @symbol(tryAgain);
+ break;
+ case EAI_SYSTEM:
+ error = @symbol(systemError);
+ break;
+ default:
+ error = @symbol(unknownError);
+ }
+ errorString = __MKSTRING(gai_strerror(ret));
+ goto err;
+ }
+# else /* ! NI_NUMERICHOST */
+ /*
+ * Do it using gethostbyaddr()
+ */
+
+ struct sockaddr_in *sa;
+ if (__byteArraySize(socketAddress) < sizeof(*sa)) {
+ error = @symbol(badArgument1);
+ goto err;
+ }
+ sa = (struct sockaddr_in *)__byteArrayVal(socketAddress);
+
+ if (sp) {
+ struct servent *servp;
+ char *__proto = 0;
+
+ __proto = (useDatagram == true ? "udp" : "tcp");
+
+ servp = getservbyport(sa->sin_port, __proto);
+ if (servp) {
+ sp = servp->s_name;
+ }
+ }
+ if (hp) {
+ struct hostent *hostp;
+# ifdef USE_H_ERRNO
+ do {
+ /* __BEGIN_INTERRUPTABLE__ is dangerous, because gethostbyname
+ * uses a static data area
+ */
+ hostp = gethostbyaddr((char *)&sa->sin_addr, sizeof(sa->sin_addr), AF_INET);
+ } while ((hp == NULL)
+ && ((h_errno == TRY_AGAIN)
+ || errno == EINTR
+# ifdef IRIX5_3
+ || (errno == ECONNREFUSED)
+# endif
+ )
+ );
+ if (hp == 0) {
+ switch (h_errno) {
+ case HOST_NOT_FOUND:
+ error = @symbol(unknownHost);
+ break;
+ case NO_ADDRESS:
+ error = @symbol(noAddress);
+ break;
+ case NO_RECOVERY:
+ error = @symbol(permanentFailure);
+ break;
+ case TRY_AGAIN:
+ error = @symbol(tryAgain);
+ break;
+ default:
+ error = @symbol(unknownError);
+ }
+ errorString = __MKSTRING(hstrerror(h_errno));
+ goto err;
+ }
+# else /* !USE_H_ERRNO */
+ hostp = gethostbyaddr(sa->sin_addr, sizeof(sa->sin_addr), AF_INET);
+ if (hostp == 0) {
+ errorString = @symbol(unknownHost);
+ error = __mkSmallInteger(-1);
+ goto err;
+ }
+# endif /* !USE_H_ERRNO*/
+ hp = hostp->h_name;
+ }
+# endif /* ! NI_NUMERICHOST */
+
+ if (hp)
+ hostName = __MKSTRING(hp);
+ if (sp)
+ serviceName = __MKSTRING(sp);
+
+err:;
+#else
+ error = @symbol(notImplemented);
+#endif
+%}.
+ error notNil ifTrue:[
+ NameLookupError raiseWith:error errorString:errorString.
+ ^ nil
+ ].
+
+ ^ Array with:hostName with:serviceName
+
+ "
+ self getNameInfo:
+ (self getAddressInfo:'localhost' serviceName:'echo'
+ domain:#inet type:#stream protocol:nil flags:nil) first socketAddress
+ wantHostName:true wantServiceName:true datagram:false flags:0
+ "
+! !
+
!UnixOperatingSystem::SocketHandle methodsFor:'accepting'!
acceptWithPeerAddressBuffer:peerOrNil
@@ -12238,7 +12767,7 @@
!UnixOperatingSystem class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.148 2003-03-26 10:24:36 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.149 2003-03-27 13:28:00 stefan Exp $'
! !
UnixOperatingSystem initialize!