1#define _GNU_SOURCE 2#include <sys/socket.h> 3#include <netinet/in.h> 4#include <netdb.h> 5#include <inttypes.h> 6#include <errno.h> 7#include <string.h> 8 9int getservbyport_r(int port, const char *prots, 10 struct servent *se, char *buf, size_t buflen, struct servent **res) 11{ 12 int i; 13 struct sockaddr_in sin = { 14 .sin_family = AF_INET, 15 .sin_port = port, 16 }; 17 18 if (!prots) { 19 int r = getservbyport_r(port, "tcp", se, buf, buflen, res); 20 if (r) r = getservbyport_r(port, "udp", se, buf, buflen, res); 21 return r; 22 } 23 *res = 0; 24 25 /* Align buffer */ 26 i = (uintptr_t)buf & sizeof(char *)-1; 27 if (!i) i = sizeof(char *); 28 if (buflen < 3*sizeof(char *)-i) 29 return ERANGE; 30 buf += sizeof(char *)-i; 31 buflen -= sizeof(char *)-i; 32 33 if (strcmp(prots, "tcp") && strcmp(prots, "udp")) return EINVAL; 34 35 se->s_port = port; 36 se->s_proto = (char *)prots; 37 se->s_aliases = (void *)buf; 38 buf += 2*sizeof(char *); 39 buflen -= 2*sizeof(char *); 40 se->s_aliases[1] = 0; 41 se->s_aliases[0] = se->s_name = buf; 42 43 switch (getnameinfo((void *)&sin, sizeof sin, 0, 0, buf, buflen, 44 strcmp(prots, "udp") ? 0 : NI_DGRAM)) { 45 case EAI_MEMORY: 46 case EAI_SYSTEM: 47 return ENOMEM; 48 default: 49 return ENOENT; 50 case 0: 51 break; 52 } 53 54 *res = se; 55 return 0; 56} 57