Commit | Line | Data |
---|---|---|
23e7e3ae JVH |
1 | /** |
2 | * Copyright (C) 2011-2012 Juho Vähä-Herttua | |
3 | * | |
4 | * This library is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU Lesser General Public | |
6 | * License as published by the Free Software Foundation; either | |
7 | * version 2.1 of the License, or (at your option) any later version. | |
8 | * | |
9 | * This library is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * Lesser General Public License for more details. | |
13 | */ | |
14 | ||
2340bcd3 JVH |
15 | #include <stdlib.h> |
16 | #include <string.h> | |
17 | #include <assert.h> | |
18 | ||
19 | #include "compat.h" | |
20 | ||
21 | int | |
22 | netutils_init() | |
23 | { | |
24 | #ifdef WIN32 | |
25 | WORD wVersionRequested; | |
26 | WSADATA wsaData; | |
27 | int ret; | |
28 | ||
29 | wVersionRequested = MAKEWORD(2, 2); | |
30 | ret = WSAStartup(wVersionRequested, &wsaData); | |
31 | if (ret) { | |
32 | return -1; | |
33 | } | |
34 | ||
35 | if (LOBYTE(wsaData.wVersion) != 2 || | |
36 | HIBYTE(wsaData.wVersion) != 2) { | |
37 | /* Version mismatch, requested version not found */ | |
38 | return -1; | |
39 | } | |
40 | #endif | |
41 | return 0; | |
42 | } | |
43 | ||
44 | void | |
45 | netutils_cleanup() | |
46 | { | |
47 | #ifdef WIN32 | |
48 | WSACleanup(); | |
49 | #endif | |
50 | } | |
51 | ||
52 | int | |
53 | netutils_init_socket(unsigned short *port, int use_ipv6, int use_udp) | |
54 | { | |
55 | int family = use_ipv6 ? AF_INET6 : AF_INET; | |
56 | int type = use_udp ? SOCK_DGRAM : SOCK_STREAM; | |
57 | int proto = use_udp ? IPPROTO_UDP : IPPROTO_TCP; | |
58 | ||
59 | struct sockaddr_storage saddr; | |
60 | socklen_t socklen; | |
61 | int server_fd; | |
62 | int ret; | |
63 | ||
64 | assert(port); | |
65 | ||
66 | server_fd = socket(family, type, proto); | |
67 | if (server_fd == -1) { | |
68 | goto cleanup; | |
69 | } | |
70 | ||
71 | memset(&saddr, 0, sizeof(saddr)); | |
72 | if (use_ipv6) { | |
73 | struct sockaddr_in6 *sin6ptr = (struct sockaddr_in6 *)&saddr; | |
870f342f | 74 | int v6only = 1; |
2340bcd3 JVH |
75 | |
76 | /* Initialize sockaddr for bind */ | |
77 | sin6ptr->sin6_family = family; | |
78 | sin6ptr->sin6_addr = in6addr_any; | |
79 | sin6ptr->sin6_port = htons(*port); | |
80 | ||
64d59e30 | 81 | #ifndef WIN32 |
870f342f JVH |
82 | /* Make sure we only listen to IPv6 addresses */ |
83 | setsockopt(server_fd, IPPROTO_IPV6, IPV6_V6ONLY, | |
84 | (char *) &v6only, sizeof(v6only)); | |
64d59e30 | 85 | #endif |
e161255a | 86 | |
2340bcd3 JVH |
87 | socklen = sizeof(*sin6ptr); |
88 | ret = bind(server_fd, (struct sockaddr *)sin6ptr, socklen); | |
89 | if (ret == -1) { | |
90 | goto cleanup; | |
91 | } | |
92 | ||
93 | ret = getsockname(server_fd, (struct sockaddr *)sin6ptr, &socklen); | |
94 | if (ret == -1) { | |
95 | goto cleanup; | |
96 | } | |
97 | *port = ntohs(sin6ptr->sin6_port); | |
98 | } else { | |
99 | struct sockaddr_in *sinptr = (struct sockaddr_in *)&saddr; | |
100 | ||
101 | /* Initialize sockaddr for bind */ | |
102 | sinptr->sin_family = family; | |
103 | sinptr->sin_addr.s_addr = INADDR_ANY; | |
104 | sinptr->sin_port = htons(*port); | |
105 | ||
106 | socklen = sizeof(*sinptr); | |
107 | ret = bind(server_fd, (struct sockaddr *)sinptr, socklen); | |
108 | if (ret == -1) { | |
109 | goto cleanup; | |
110 | } | |
111 | ||
112 | ret = getsockname(server_fd, (struct sockaddr *)sinptr, &socklen); | |
113 | if (ret == -1) { | |
114 | goto cleanup; | |
115 | } | |
116 | *port = ntohs(sinptr->sin_port); | |
117 | } | |
118 | return server_fd; | |
119 | ||
120 | cleanup: | |
121 | ret = SOCKET_GET_ERROR(); | |
122 | if (server_fd != -1) { | |
123 | closesocket(server_fd); | |
124 | } | |
125 | SOCKET_SET_ERROR(ret); | |
126 | return -1; | |
127 | } | |
128 | ||
129 | unsigned char * | |
130 | netutils_get_address(void *sockaddr, int *length) | |
131 | { | |
132 | unsigned char ipv4_prefix[] = { 0,0,0,0,0,0,0,0,0,0,255,255 }; | |
133 | struct sockaddr *address = sockaddr; | |
134 | ||
135 | assert(address); | |
136 | assert(length); | |
137 | ||
138 | if (address->sa_family == AF_INET) { | |
139 | struct sockaddr_in *sin; | |
140 | ||
141 | sin = (struct sockaddr_in *)address; | |
142 | *length = sizeof(sin->sin_addr.s_addr); | |
143 | return (unsigned char *)&sin->sin_addr.s_addr; | |
144 | } else if (address->sa_family == AF_INET6) { | |
145 | struct sockaddr_in6 *sin6; | |
146 | ||
147 | sin6 = (struct sockaddr_in6 *)address; | |
148 | if (!memcmp(sin6->sin6_addr.s6_addr, ipv4_prefix, 12)) { | |
149 | /* Actually an embedded IPv4 address */ | |
150 | *length = sizeof(sin6->sin6_addr.s6_addr)-12; | |
151 | return (sin6->sin6_addr.s6_addr+12); | |
152 | } | |
153 | *length = sizeof(sin6->sin6_addr.s6_addr); | |
154 | return sin6->sin6_addr.s6_addr; | |
155 | } | |
156 | ||
157 | *length = 0; | |
158 | return NULL; | |
159 | } | |
160 | ||
ba0970e1 JVH |
161 | int |
162 | netutils_parse_address(int family, const char *src, void *dst, int dstlen) | |
163 | { | |
164 | struct addrinfo *result; | |
165 | struct addrinfo *ptr; | |
166 | struct addrinfo hints; | |
167 | int length; | |
168 | int ret; | |
169 | ||
170 | if (family != AF_INET && family != AF_INET6) { | |
171 | return -1; | |
172 | } | |
173 | if (!src || !dst) { | |
174 | return -1; | |
175 | } | |
176 | ||
177 | memset(&hints, 0, sizeof(hints)); | |
178 | hints.ai_family = family; | |
179 | hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; | |
180 | ||
181 | ret = getaddrinfo(src, NULL, &hints, &result); | |
182 | if (ret != 0) { | |
183 | return -1; | |
184 | } | |
185 | ||
186 | length = -1; | |
187 | for (ptr=result; ptr!=NULL; ptr=ptr->ai_next) { | |
566c9bf8 | 188 | if (family == ptr->ai_family && (unsigned int)dstlen >= ptr->ai_addrlen) { |
ba0970e1 JVH |
189 | memcpy(dst, ptr->ai_addr, ptr->ai_addrlen); |
190 | length = ptr->ai_addrlen; | |
191 | break; | |
192 | } | |
193 | } | |
194 | freeaddrinfo(result); | |
195 | return length; | |
196 | } |