# HG changeset patch # User Stefan Vogel # Date 1282156400 -7200 # Node ID c16326b73bf0aa7f0c76134273e3011b543ac137 # Parent 089f3e80f4a391eef03723e19c9aed98b04886fd getAddressInfo:... - try UNLIMITEDSTACK diff -r 089f3e80f4a3 -r c16326b73bf0 UnixOperatingSystem.st --- a/UnixOperatingSystem.st Wed Aug 18 10:44:40 2010 +0200 +++ b/UnixOperatingSystem.st Wed Aug 18 20:33:20 2010 +0200 @@ -11252,7 +11252,7 @@ !UnixOperatingSystem::SocketHandle class methodsFor:'queries'! -getAddressInfo:hostName serviceName:serviceNameArg domain:domainArg type:typeArg protocol:protoArg flags:flags +XXgetAddressInfo:hostName serviceName:serviceNameArg 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." @@ -11626,6 +11626,76 @@ " ! +getAddressInfo:hostName serviceName:serviceNameArg 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." + + |result domain type proto serviceName| + + domain := OperatingSystem domainCodeOf:domainArg. + type := OperatingSystem socketTypeCodeOf:typeArg. + proto := self protocolCodeOf:protoArg. + serviceNameArg notNil ifTrue:[ + serviceName := serviceNameArg printString. "convert integer port numbers" + ]. + + result := self primGetAddressInfo:hostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto flags:flags. + result isArray ifFalse:[ + |request| + request := SocketAddressInfo new + domain:domainArg; + type:typeArg; + protocol:protoArg; + canonicalName:hostName; + serviceName:serviceName. + ^ (HostNameLookupError new + parameter:result; + messageText:' - ', (result printString); + request:request) raiseRequest. + ]. + 1 to:result size do:[:i | + |entry dom info| + + entry := result at:i. + + info := SocketAddressInfo new. + info + flags:(entry at:1); + domain:(dom := OperatingSystem domainSymbolOf:(entry at:2)); + type:(OperatingSystem socketTypeSymbolOf:(entry at:3)); + protocol:(self protocolSymbolOf:(entry at:4)); + socketAddress:((SocketAddress newDomain:dom) fromBytes:(entry at:5)); + 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 + self getAddressInfo:'www.google.de' serviceName:nil + domain:nil type:nil protocol:nil flags:nil + self getAddressInfo:'smc1' serviceName:nil + domain:nil 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. @@ -11857,6 +11927,327 @@ domain:#inet type:#stream protocol:nil flags:nil) first socketAddress wantHostName:true wantServiceName:true datagram:false flags:0 " +! + +primGetAddressInfo:hostName serviceName:serviceName domainCode:domain socketTypeCode:type protocolCode:proto 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| + +%{ /* UNLIMITEDSTACK */ /* Don't know whether DNS, NIS, LDAP or whatever is consulted */ +#undef xxAI_NUMERICHOST /* remove xx to test gethost...() path */ + + +#if !defined(NO_SOCKET) + char *__hostName, *__serviceName; + int ret, cnt = 0; + + if (hostName == nil) { + __hostName = 0; + } else if (__isStringLike(hostName)) { + __hostName = __stringVal(hostName); + } else { + error = @symbol(badArgument1); + goto err; + } + if (serviceName == nil) { + __serviceName = 0; + } else if (__isStringLike(serviceName)) { + __serviceName = __stringVal(serviceName); + } else { + error = @symbol(badArgument2); + goto err; + } + if (__hostName == 0 && __serviceName == 0) { + error = @symbol(badArgument); + goto err; + } + +{ +# if defined(AI_NUMERICHOST) + /* + * Use getaddrinfo() + */ + struct addrinfo hints; + struct addrinfo *info = NULL, *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 { + if (hostName == nil) { + __hostName = 0; + } else if (__isStringLike(hostName)) { + __hostName = __stringVal(hostName); + } + if (serviceName == nil) { + __serviceName = 0; + } else if (__isStringLike(serviceName)) { + __serviceName = __stringVal(serviceName); + } + +// __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; +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY : + error = @symbol(unknownHostForProtocol); + break; +#endif +#ifdef EAI_NODATA + case EAI_NODATA: + error = @symbol(noAddress); + break; +#endif + 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] = __mkSmallInteger(infop->ai_flags); + __ArrayInstPtr(resp)->a_element[1] = __mkSmallInteger(infop->ai_family); + __ArrayInstPtr(resp)->a_element[2] = __mkSmallInteger(infop->ai_socktype); + __ArrayInstPtr(resp)->a_element[3] = __mkSmallInteger(infop->ai_protocol); + + __PROTECT__(resp); + o = __BYTEARRAY_NEW_INT(infop->ai_addrlen); + __UNPROTECT__(resp); + 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) { + __PROTECT__(resp); + o = __MKSTRING(infop->ai_canonname); + __UNPROTECT__(resp); + 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 =============================================================*/ + + /* + * Use getservbyname() / gethostByName() + */ + struct hostent *hp; + char **addrpp; + int port = 0; + int i; + + if (__serviceName) { + struct servent *sp; + char *__proto = 0; + + if (__isStringLike(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 { + if (hostName == nil) { + __hostName = 0; + } else if (__isStringLike(hostName)) { + __hostName = __stringVal(hostName); + } + /* __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: + errorString = @symbol(unknownHost); + break; + case NO_ADDRESS: + errorString = @symbol(noAddress); + break; + case NO_RECOVERY: + errorString = @symbol(permanentFailure); + break; + case TRY_AGAIN: + errorString = @symbol(tryAgain); + break; + default: + errorString = @symbol(unknownError); + break; + } + error = __mkSmallInteger(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; __STORE(result, type); + __ArrayInstPtr(resp)->a_element[3] = proto; __STORE(result, proto); + __PROTECT__(resp); + o = __BYTEARRAY_NEW_INT(sizeof(*sa)); + __UNPROTECT__(resp); + 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) { + __PROTECT__(resp); + o = __MKSTRING(hp->h_name); + __UNPROTECT__(resp); + 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; __STORE(resp, domain); + } + } + +err:; +# endif /* ! AI_NUMERICHOST */ +} +#else /* ! HAS_SOCKET */ + error = @symbol(notImplemented); +#endif +%}. + error notNil ifTrue:[ + errorString notNil ifTrue:[ + ^ errorString. + ]. + ^ error. + ]. + ^ result. ! ! !UnixOperatingSystem::SocketHandle methodsFor:'accepting'! @@ -12700,11 +13091,11 @@ !UnixOperatingSystem class methodsFor:'documentation'! version - ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.276 2010-07-27 09:08:07 stefan Exp $' + ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.277 2010-08-18 18:33:20 stefan Exp $' ! version_CVS - ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.276 2010-07-27 09:08:07 stefan Exp $' + ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.277 2010-08-18 18:33:20 stefan Exp $' ! ! UnixOperatingSystem initialize!