make getaddrinfo support SOCK_RAW and other socket types
authorRich Felker <dalias@aerifal.cx>
Sat, 7 Feb 2015 19:01:34 +0000 (14:01 -0500)
committerRich Felker <dalias@aerifal.cx>
Sat, 7 Feb 2015 19:01:34 +0000 (14:01 -0500)
all socket types are accepted at this point, but that may be changed
at a later time if the behavior is not meaningful for other types. as
before, omitting type (a value of 0) gives both UDP and TCP results,
and SOCK_DGRAM or SOCK_STREAM restricts to UDP or TCP, respectively.
for other socket types, the service name argument is required to be a
null pointer, and the protocol number provided by the caller is used.

src/network/getaddrinfo.c
src/network/getservbyname_r.c
src/network/lookup.h
src/network/lookup_serv.c

index d991344..c88d558 100644 (file)
@@ -11,7 +11,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
        struct address addrs[MAXADDRS];
        char canon[256], *outcanon;
        int nservs, naddrs, nais, canon_len, i, j, k;
-       int family = AF_UNSPEC, flags = 0, proto = 0;
+       int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0;
        struct aibuf {
                struct addrinfo ai;
                union sa {
@@ -24,6 +24,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
                family = hint->ai_family;
                flags = hint->ai_flags;
                proto = hint->ai_protocol;
+               socktype = hint->ai_socktype;
 
                const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST |
                        AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV;
@@ -38,35 +39,9 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
                default:
                        return EAI_FAMILY;
                }
-
-               switch (hint->ai_socktype) {
-               case SOCK_STREAM:
-                       switch (proto) {
-                       case 0:
-                               proto = IPPROTO_TCP;
-                       case IPPROTO_TCP:
-                               break;
-                       default:
-                               return EAI_SERVICE;
-                       }
-                       break;
-               case SOCK_DGRAM:
-                       switch (proto) {
-                       case 0:
-                               proto = IPPROTO_UDP;
-                       case IPPROTO_UDP:
-                               break;
-                       default:
-                               return EAI_SERVICE;
-                       }
-               case 0:
-                       break;
-               default:
-                       return EAI_SOCKTYPE;
-               }
        }
 
-       nservs = __lookup_serv(ports, serv, proto, flags);
+       nservs = __lookup_serv(ports, serv, proto, socktype, flags);
        if (nservs < 0) return nservs;
 
        naddrs = __lookup_name(addrs, canon, host, family, flags);
@@ -87,8 +62,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
        for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) {
                out[k].ai = (struct addrinfo){
                        .ai_family = addrs[i].family,
-                       .ai_socktype = ports[j].proto == IPPROTO_TCP
-                               ? SOCK_STREAM : SOCK_DGRAM,
+                       .ai_socktype = ports[j].socktype,
                        .ai_protocol = ports[j].proto,
                        .ai_addrlen = addrs[i].family == AF_INET
                                ? sizeof(struct sockaddr_in)
index 8cdf622..056c2f3 100644 (file)
@@ -26,7 +26,7 @@ int getservbyname_r(const char *name, const char *prots,
        else if (!strcmp(prots, "udp")) proto = IPPROTO_UDP;
        else return EINVAL;
 
-       cnt = __lookup_serv(servs, name, proto, 0);
+       cnt = __lookup_serv(servs, name, proto, 0, 0);
        if (cnt<0) switch (cnt) {
        case EAI_MEMORY:
        case EAI_SYSTEM:
index 4e45d86..6941911 100644 (file)
@@ -12,7 +12,7 @@ struct address {
 
 struct service {
        uint16_t port;
-       char proto;
+       unsigned char proto, socktype;
 };
 
 /* The limit of 48 results is a non-sharp bound on the number of addresses
@@ -21,7 +21,7 @@ struct service {
 #define MAXADDRS 48
 #define MAXSERVS 2
 
-int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int flags);
+int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags);
 int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags);
 int __lookup_ipliteral(struct address buf[static 1], const char *name, int family);
 
index a9be0f3..4faa5bc 100644 (file)
@@ -7,13 +7,43 @@
 #include "lookup.h"
 #include "stdio_impl.h"
 
-int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int flags)
+int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags)
 {
        char line[128];
        int cnt = 0;
        char *p, *z = "";
        unsigned long port = 0;
 
+       switch (socktype) {
+       case SOCK_STREAM:
+               switch (proto) {
+               case 0:
+                       proto = IPPROTO_TCP;
+               case IPPROTO_TCP:
+                       break;
+               default:
+                       return EAI_SERVICE;
+               }
+               break;
+       case SOCK_DGRAM:
+               switch (proto) {
+               case 0:
+                       proto = IPPROTO_UDP;
+               case IPPROTO_UDP:
+                       break;
+               default:
+                       return EAI_SERVICE;
+               }
+       case 0:
+               break;
+       default:
+               if (name) return EAI_SERVICE;
+               buf[0].port = 0;
+               buf[0].proto = proto;
+               buf[0].socktype = socktype;
+               return 1;
+       }
+
        if (name) {
                if (!*name) return EAI_SERVICE;
                port = strtoul(name, &z, 10);
@@ -22,10 +52,12 @@ int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int pro
                if (port > 65535) return EAI_SERVICE;
                if (proto != IPPROTO_UDP) {
                        buf[cnt].port = port;
+                       buf[cnt].socktype = SOCK_STREAM;
                        buf[cnt++].proto = IPPROTO_TCP;
                }
                if (proto != IPPROTO_TCP) {
                        buf[cnt].port = port;
+                       buf[cnt].socktype = SOCK_DGRAM;
                        buf[cnt++].proto = IPPROTO_UDP;
                }
                return cnt;
@@ -58,11 +90,13 @@ int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int pro
                if (!strncmp(z, "/udp", 4)) {
                        if (proto == IPPROTO_TCP) continue;
                        buf[cnt].port = port;
+                       buf[cnt].socktype = SOCK_DGRAM;
                        buf[cnt++].proto = IPPROTO_UDP;
                }
                if (!strncmp(z, "/tcp", 4)) {
                        if (proto == IPPROTO_UDP) continue;
                        buf[cnt].port = port;
+                       buf[cnt].socktype = SOCK_STREAM;
                        buf[cnt++].proto = IPPROTO_TCP;
                }
        }