| 1 | /* | 
| 2 |  * librd - Rapid Development C library | 
| 3 |  * | 
| 4 |  * Copyright (c) 2012, Magnus Edenhill | 
| 5 |  * All rights reserved. | 
| 6 |  *  | 
| 7 |  * Redistribution and use in source and binary forms, with or without | 
| 8 |  * modification, are permitted provided that the following conditions are met:  | 
| 9 |  *  | 
| 10 |  * 1. Redistributions of source code must retain the above copyright notice, | 
| 11 |  *    this list of conditions and the following disclaimer.  | 
| 12 |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
| 13 |  *    this list of conditions and the following disclaimer in the documentation | 
| 14 |  *    and/or other materials provided with the distribution.  | 
| 15 |  *  | 
| 16 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
| 17 |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  | 
| 18 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  | 
| 19 |  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE  | 
| 20 |  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  | 
| 21 |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  | 
| 22 |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  | 
| 23 |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  | 
| 24 |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
| 25 |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 
| 26 |  * POSSIBILITY OF SUCH DAMAGE. | 
| 27 |  */ | 
| 28 |  | 
| 29 |  | 
| 30 | #include "rd.h" | 
| 31 | #include "rdaddr.h" | 
| 32 | #include "rdrand.h" | 
| 33 |  | 
| 34 | #ifdef _MSC_VER | 
| 35 | #include <WS2tcpip.h> | 
| 36 | #endif | 
| 37 |  | 
| 38 | const char *rd_sockaddr2str (const void *addr, int flags) { | 
| 39 | 	const rd_sockaddr_inx_t *a = (const rd_sockaddr_inx_t *)addr; | 
| 40 | 	static RD_TLS char ret[32][INET6_ADDRSTRLEN + 16]; | 
| 41 | 	static RD_TLS int  reti = 0; | 
| 42 | 	char portstr[64]; | 
| 43 | 	int of = 0; | 
| 44 | 	int niflags = NI_NUMERICSERV; | 
| 45 |  | 
| 46 | 	reti = (reti + 1) % 32; | 
| 47 | 	 | 
| 48 | 	switch (a->sinx_family) | 
| 49 | 	{ | 
| 50 | 	case AF_INET: | 
| 51 | 	case AF_INET6: | 
| 52 | 		if (flags & RD_SOCKADDR2STR_F_FAMILY) | 
| 53 | 			of += rd_snprintf(&ret[reti][of], sizeof(ret[reti])-of, "ipv%i#" , | 
| 54 | 				      a->sinx_family == AF_INET ? 4 : 6); | 
| 55 |  | 
| 56 | 		if ((flags & RD_SOCKADDR2STR_F_PORT) && | 
| 57 | 		    a->sinx_family == AF_INET6) | 
| 58 | 			ret[reti][of++] = '['; | 
| 59 |  | 
| 60 | 		if (!(flags & RD_SOCKADDR2STR_F_RESOLVE)) | 
| 61 | 			niflags |= NI_NUMERICHOST; | 
| 62 |  | 
| 63 | 		if (getnameinfo((const struct sockaddr *)a, | 
| 64 | 				RD_SOCKADDR_INX_LEN(a), | 
| 65 | 				ret[reti]+of, sizeof(ret[reti])-of, | 
| 66 | 				(flags & RD_SOCKADDR2STR_F_PORT) ? | 
| 67 | 				portstr : NULL, | 
| 68 | 				(flags & RD_SOCKADDR2STR_F_PORT) ? | 
| 69 | 				sizeof(portstr) : 0, | 
| 70 | 				niflags)) | 
| 71 | 			break; | 
| 72 |  | 
| 73 | 		 | 
| 74 | 		if (flags & RD_SOCKADDR2STR_F_PORT) { | 
| 75 | 			size_t len = strlen(ret[reti]); | 
| 76 | 			rd_snprintf(ret[reti]+len, sizeof(ret[reti])-len, | 
| 77 | 				 "%s:%s" , | 
| 78 | 				 a->sinx_family == AF_INET6 ? "]"  : "" , | 
| 79 | 				 portstr); | 
| 80 | 		} | 
| 81 | 	 | 
| 82 | 		return ret[reti]; | 
| 83 | 	} | 
| 84 | 	 | 
| 85 |  | 
| 86 | 	/* Error-case */ | 
| 87 | 	rd_snprintf(ret[reti], sizeof(ret[reti]), "<unsupported:%s>" , | 
| 88 | 		 rd_family2str(a->sinx_family)); | 
| 89 | 	 | 
| 90 | 	return ret[reti]; | 
| 91 | } | 
| 92 |  | 
| 93 |  | 
| 94 | const char *rd_addrinfo_prepare (const char *nodesvc, | 
| 95 | 				 char **node, char **svc) { | 
| 96 | 	static RD_TLS char snode[256]; | 
| 97 | 	static RD_TLS char ssvc[64]; | 
| 98 | 	const char *t; | 
| 99 | 	const char *svct = NULL; | 
| 100 | 	size_t nodelen = 0; | 
| 101 |  | 
| 102 | 	*snode = '\0'; | 
| 103 | 	*ssvc = '\0'; | 
| 104 |  | 
| 105 | 	if (*nodesvc == '[') { | 
| 106 | 		/* "[host]".. (enveloped node name) */ | 
| 107 | 		if  (!(t = strchr(nodesvc, ']'))) | 
| 108 | 			return "Missing close-']'" ; | 
| 109 | 		nodesvc++; | 
| 110 | 		nodelen = t-nodesvc; | 
| 111 | 		svct = t+1; | 
| 112 |  | 
| 113 | 	} else if (*nodesvc == ':' && *(nodesvc+1) != ':') { | 
| 114 | 		/* ":"..  (port only) */ | 
| 115 | 		nodelen = 0; | 
| 116 | 		svct = nodesvc; | 
| 117 | 	} | 
| 118 | 		 | 
| 119 | 	if ((svct = strrchr(svct ? svct : nodesvc, ':')) && (*(svct-1) != ':') && | 
| 120 | 	    *(++svct)) { | 
| 121 | 		/* Optional ":service" definition. */ | 
| 122 | 		if (strlen(svct) >= sizeof(ssvc)) | 
| 123 | 			return "Service name too long" ; | 
| 124 | 		strcpy(ssvc, svct); | 
| 125 | 		if (!nodelen) | 
| 126 | 			nodelen = svct - nodesvc - 1; | 
| 127 |  | 
| 128 | 	} else if (!nodelen) | 
| 129 | 		nodelen = strlen(nodesvc); | 
| 130 |  | 
| 131 | 	if (nodelen) { | 
| 132 | 		/* Truncate nodename if necessary. */ | 
| 133 | 		nodelen = RD_MIN(nodelen, sizeof(snode)-1); | 
| 134 | 		memcpy(snode, nodesvc, nodelen); | 
| 135 | 		snode[nodelen] = '\0'; | 
| 136 | 	} | 
| 137 |  | 
| 138 | 	*node = snode; | 
| 139 | 	*svc = ssvc; | 
| 140 |  | 
| 141 | 	return NULL; | 
| 142 | } | 
| 143 |  | 
| 144 |  | 
| 145 |  | 
| 146 | rd_sockaddr_list_t *rd_getaddrinfo (const char *nodesvc, const char *defsvc, | 
| 147 | 				    int flags, int family, | 
| 148 | 				    int socktype, int protocol, | 
| 149 | 				    const char **errstr) { | 
| 150 | 	struct addrinfo hints = { .ai_family = family, | 
| 151 | 				  .ai_socktype = socktype, | 
| 152 | 				  .ai_protocol = protocol, | 
| 153 | 				  .ai_flags = flags }; | 
| 154 | 	struct addrinfo *ais, *ai; | 
| 155 | 	char *node, *svc; | 
| 156 | 	int r; | 
| 157 | 	int cnt = 0; | 
| 158 | 	rd_sockaddr_list_t *rsal; | 
| 159 |  | 
| 160 | 	if ((*errstr = rd_addrinfo_prepare(nodesvc, &node, &svc))) { | 
| 161 | 		errno = EINVAL; | 
| 162 | 		return NULL; | 
| 163 | 	} | 
| 164 |  | 
| 165 | 	if (*svc) | 
| 166 | 		defsvc = svc; | 
| 167 | 		 | 
| 168 | 	if ((r = getaddrinfo(node, defsvc, &hints, &ais))) { | 
| 169 | #ifdef EAI_SYSTEM | 
| 170 | 		if (r == EAI_SYSTEM) | 
| 171 | #else | 
| 172 | 		if (0) | 
| 173 | #endif | 
| 174 | 			*errstr = rd_strerror(errno); | 
| 175 | 		else { | 
| 176 | #ifdef _MSC_VER | 
| 177 | 			*errstr = gai_strerrorA(r); | 
| 178 | #else | 
| 179 | 			*errstr = gai_strerror(r); | 
| 180 | #endif | 
| 181 | 			errno = EFAULT; | 
| 182 | 		} | 
| 183 | 		return NULL; | 
| 184 | 	} | 
| 185 | 	 | 
| 186 | 	/* Count number of addresses */ | 
| 187 | 	for (ai = ais ; ai != NULL ; ai = ai->ai_next) | 
| 188 | 		cnt++; | 
| 189 |  | 
| 190 | 	if (cnt == 0) { | 
| 191 | 		/* unlikely? */ | 
| 192 | 		freeaddrinfo(ais); | 
| 193 | 		errno = ENOENT; | 
| 194 | 		*errstr = "No addresses" ; | 
| 195 | 		return NULL; | 
| 196 | 	} | 
| 197 |  | 
| 198 |  | 
| 199 | 	rsal = rd_calloc(1, sizeof(*rsal) + (sizeof(*rsal->rsal_addr) * cnt)); | 
| 200 |  | 
| 201 | 	for (ai = ais ; ai != NULL ; ai = ai->ai_next) | 
| 202 | 		memcpy(&rsal->rsal_addr[rsal->rsal_cnt++], | 
| 203 | 		       ai->ai_addr, ai->ai_addrlen); | 
| 204 |  | 
| 205 | 	freeaddrinfo(ais); | 
| 206 |  | 
| 207 | 	/* Shuffle address list for proper round-robin */ | 
| 208 | 	if (!(flags & RD_AI_NOSHUFFLE)) | 
| 209 | 		rd_array_shuffle(rsal->rsal_addr, rsal->rsal_cnt, | 
| 210 | 				 sizeof(*rsal->rsal_addr)); | 
| 211 |  | 
| 212 | 	return rsal; | 
| 213 | } | 
| 214 |  | 
| 215 |  | 
| 216 |  | 
| 217 | void rd_sockaddr_list_destroy (rd_sockaddr_list_t *rsal) { | 
| 218 | 	rd_free(rsal); | 
| 219 | } | 
| 220 |  | 
| 221 |  |