diff -r 068fc25d90b9 -r aedf0aa8273b UnixOperatingSystem.st --- 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!