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; | |
e161255a | 74 | int v6only = 0; |
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 | ||
e161255a JVH |
81 | /* Make sure we also listen to IPv4 addresses */ |
82 | ret = setsockopt(server_fd, IPPROTO_IPV6, IPV6_V6ONLY, | |
83 | (char *) &v6only, sizeof(v6only)); | |
84 | if (ret == -1) { | |
85 | goto cleanup; | |
86 | } | |
87 | ||
2340bcd3 JVH |
88 | socklen = sizeof(*sin6ptr); |
89 | ret = bind(server_fd, (struct sockaddr *)sin6ptr, socklen); | |
90 | if (ret == -1) { | |
91 | goto cleanup; | |
92 | } | |
93 | ||
94 | ret = getsockname(server_fd, (struct sockaddr *)sin6ptr, &socklen); | |
95 | if (ret == -1) { | |
96 | goto cleanup; | |
97 | } | |
98 | *port = ntohs(sin6ptr->sin6_port); | |
99 | } else { | |
100 | struct sockaddr_in *sinptr = (struct sockaddr_in *)&saddr; | |
101 | ||
102 | /* Initialize sockaddr for bind */ | |
103 | sinptr->sin_family = family; | |
104 | sinptr->sin_addr.s_addr = INADDR_ANY; | |
105 | sinptr->sin_port = htons(*port); | |
106 | ||
107 | socklen = sizeof(*sinptr); | |
108 | ret = bind(server_fd, (struct sockaddr *)sinptr, socklen); | |
109 | if (ret == -1) { | |
110 | goto cleanup; | |
111 | } | |
112 | ||
113 | ret = getsockname(server_fd, (struct sockaddr *)sinptr, &socklen); | |
114 | if (ret == -1) { | |
115 | goto cleanup; | |
116 | } | |
117 | *port = ntohs(sinptr->sin_port); | |
118 | } | |
119 | return server_fd; | |
120 | ||
121 | cleanup: | |
122 | ret = SOCKET_GET_ERROR(); | |
123 | if (server_fd != -1) { | |
124 | closesocket(server_fd); | |
125 | } | |
126 | SOCKET_SET_ERROR(ret); | |
127 | return -1; | |
128 | } | |
129 | ||
130 | unsigned char * | |
131 | netutils_get_address(void *sockaddr, int *length) | |
132 | { | |
133 | unsigned char ipv4_prefix[] = { 0,0,0,0,0,0,0,0,0,0,255,255 }; | |
134 | struct sockaddr *address = sockaddr; | |
135 | ||
136 | assert(address); | |
137 | assert(length); | |
138 | ||
139 | if (address->sa_family == AF_INET) { | |
140 | struct sockaddr_in *sin; | |
141 | ||
142 | sin = (struct sockaddr_in *)address; | |
143 | *length = sizeof(sin->sin_addr.s_addr); | |
144 | return (unsigned char *)&sin->sin_addr.s_addr; | |
145 | } else if (address->sa_family == AF_INET6) { | |
146 | struct sockaddr_in6 *sin6; | |
147 | ||
148 | sin6 = (struct sockaddr_in6 *)address; | |
149 | if (!memcmp(sin6->sin6_addr.s6_addr, ipv4_prefix, 12)) { | |
150 | /* Actually an embedded IPv4 address */ | |
151 | *length = sizeof(sin6->sin6_addr.s6_addr)-12; | |
152 | return (sin6->sin6_addr.s6_addr+12); | |
153 | } | |
154 | *length = sizeof(sin6->sin6_addr.s6_addr); | |
155 | return sin6->sin6_addr.s6_addr; | |
156 | } | |
157 | ||
158 | *length = 0; | |
159 | return NULL; | |
160 | } | |
161 | ||
ba0970e1 JVH |
162 | int |
163 | netutils_parse_address(int family, const char *src, void *dst, int dstlen) | |
164 | { | |
165 | struct addrinfo *result; | |
166 | struct addrinfo *ptr; | |
167 | struct addrinfo hints; | |
168 | int length; | |
169 | int ret; | |
170 | ||
171 | if (family != AF_INET && family != AF_INET6) { | |
172 | return -1; | |
173 | } | |
174 | if (!src || !dst) { | |
175 | return -1; | |
176 | } | |
177 | ||
178 | memset(&hints, 0, sizeof(hints)); | |
179 | hints.ai_family = family; | |
180 | hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; | |
181 | ||
182 | ret = getaddrinfo(src, NULL, &hints, &result); | |
183 | if (ret != 0) { | |
184 | return -1; | |
185 | } | |
186 | ||
187 | length = -1; | |
188 | for (ptr=result; ptr!=NULL; ptr=ptr->ai_next) { | |
566c9bf8 | 189 | if (family == ptr->ai_family && (unsigned int)dstlen >= ptr->ai_addrlen) { |
ba0970e1 JVH |
190 | memcpy(dst, ptr->ai_addr, ptr->ai_addrlen); |
191 | length = ptr->ai_addrlen; | |
192 | break; | |
193 | } | |
194 | } | |
195 | freeaddrinfo(result); | |
196 | return length; | |
197 | } |