make dlerror state and message thread-local and dynamically-allocated
[oweals/musl.git] / src / network / lookup_serv.c
1 #include <sys/socket.h>
2 #include <netinet/in.h>
3 #include <netdb.h>
4 #include <ctype.h>
5 #include <string.h>
6 #include <fcntl.h>
7 #include "lookup.h"
8 #include "stdio_impl.h"
9
10 int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags)
11 {
12         char line[128];
13         int cnt = 0;
14         char *p, *z = "";
15         unsigned long port = 0;
16
17         switch (socktype) {
18         case SOCK_STREAM:
19                 switch (proto) {
20                 case 0:
21                         proto = IPPROTO_TCP;
22                 case IPPROTO_TCP:
23                         break;
24                 default:
25                         return EAI_SERVICE;
26                 }
27                 break;
28         case SOCK_DGRAM:
29                 switch (proto) {
30                 case 0:
31                         proto = IPPROTO_UDP;
32                 case IPPROTO_UDP:
33                         break;
34                 default:
35                         return EAI_SERVICE;
36                 }
37         case 0:
38                 break;
39         default:
40                 if (name) return EAI_SERVICE;
41                 buf[0].port = 0;
42                 buf[0].proto = proto;
43                 buf[0].socktype = socktype;
44                 return 1;
45         }
46
47         if (name) {
48                 if (!*name) return EAI_SERVICE;
49                 port = strtoul(name, &z, 10);
50         }
51         if (!*z) {
52                 if (port > 65535) return EAI_SERVICE;
53                 if (proto != IPPROTO_UDP) {
54                         buf[cnt].port = port;
55                         buf[cnt].socktype = SOCK_STREAM;
56                         buf[cnt++].proto = IPPROTO_TCP;
57                 }
58                 if (proto != IPPROTO_TCP) {
59                         buf[cnt].port = port;
60                         buf[cnt].socktype = SOCK_DGRAM;
61                         buf[cnt++].proto = IPPROTO_UDP;
62                 }
63                 return cnt;
64         }
65
66         if (flags & AI_NUMERICSERV) return EAI_SERVICE;
67
68         size_t l = strlen(name);
69
70         unsigned char _buf[1032];
71         FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf);
72         if (!f) return EAI_SERVICE;
73
74         while (fgets(line, sizeof line, f) && cnt < MAXSERVS) {
75                 if ((p=strchr(line, '#'))) *p++='\n', *p=0;
76
77                 /* Find service name */
78                 for(p=line; (p=strstr(p, name)); p++) {
79                         if (p>line && !isspace(p[-1])) continue;
80                         if (p[l] && !isspace(p[l])) continue;
81                         break;
82                 }
83                 if (!p) continue;
84
85                 /* Skip past canonical name at beginning of line */
86                 for (p=line; *p && !isspace(*p); p++);
87
88                 port = strtoul(p, &z, 10);
89                 if (port > 65535 || z==p) continue;
90                 if (!strncmp(z, "/udp", 4)) {
91                         if (proto == IPPROTO_TCP) continue;
92                         buf[cnt].port = port;
93                         buf[cnt].socktype = SOCK_DGRAM;
94                         buf[cnt++].proto = IPPROTO_UDP;
95                 }
96                 if (!strncmp(z, "/tcp", 4)) {
97                         if (proto == IPPROTO_UDP) continue;
98                         buf[cnt].port = port;
99                         buf[cnt].socktype = SOCK_STREAM;
100                         buf[cnt++].proto = IPPROTO_TCP;
101                 }
102         }
103         __fclose_ca(f);
104         return cnt > 0 ? cnt : EAI_SERVICE;
105 }