Merge branch 'master' of git://repo.or.cz/unleashed
[unleashed.git] / contrib / libjeffpc / sock.c
blob357858a9170f098486685224b5dc3ae992453730
1 /*
2 * Copyright (c) 2016 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
23 #include <sys/socket.h>
24 #include <netdb.h>
25 #include <unistd.h>
27 #include <jeffpc/sock.h>
29 int connect_ip(const char *host, uint16_t port, bool v4, bool v6, enum ip_type type)
31 struct addrinfo hints, *res, *p;
32 char strport[6];
33 int sock;
35 if (!host || !port || (!v4 && !v6) || (type != IP_TCP))
36 return -EINVAL;
38 memset(&hints, 0, sizeof(hints));
39 hints.ai_family = AF_UNSPEC;
40 hints.ai_socktype = SOCK_STREAM;
41 hints.ai_flags = AI_PASSIVE;
43 snprintf(strport, sizeof(strport), "%hu", port);
45 switch (getaddrinfo(host, strport, &hints, &res)) {
46 case 0:
47 /* success */
48 break;
49 case EAI_ADDRFAMILY:
50 case EAI_FAMILY:
51 case EAI_SERVICE:
52 case EAI_SOCKTYPE:
53 return -ENOTSUP;
54 case EAI_AGAIN:
55 return -EAGAIN;
56 case EAI_BADFLAGS:
57 return -EINVAL;
58 case EAI_MEMORY:
59 return -ENOMEM;
60 case EAI_NODATA:
61 case EAI_NONAME:
62 return -ENOENT;
63 case EAI_OVERFLOW:
64 return -EOVERFLOW;
65 case EAI_SYSTEM:
66 return -errno;
67 default:
68 /* TODO: is this the best errno we can return? */
69 return -ENOENT;
72 sock = -ENOENT;
74 for (p = res; p; p = p->ai_next) {
75 switch (p->ai_family) {
76 case AF_INET:
77 if (!v4)
78 continue;
79 break;
80 case AF_INET6:
81 if (!v6)
82 continue;
83 break;
84 default:
85 continue;
88 sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
89 if (sock == -1) {
90 sock = -errno;
91 continue;
94 if (connect(sock, p->ai_addr, p->ai_addrlen) == -1) {
95 close(sock);
96 sock = -errno;
97 continue;
100 /* success! */
101 break;
104 freeaddrinfo(res);
106 return sock;