Move src to src/lib, include to src/include, test to src/test.
[deb_shairplay.git] / src / lib / netutils.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <assert.h>
4
5 #include "compat.h"
6
7 int
8 netutils_init()
9 {
10 #ifdef WIN32
11 WORD wVersionRequested;
12 WSADATA wsaData;
13 int ret;
14
15 wVersionRequested = MAKEWORD(2, 2);
16 ret = WSAStartup(wVersionRequested, &wsaData);
17 if (ret) {
18 return -1;
19 }
20
21 if (LOBYTE(wsaData.wVersion) != 2 ||
22 HIBYTE(wsaData.wVersion) != 2) {
23 /* Version mismatch, requested version not found */
24 return -1;
25 }
26 #endif
27 return 0;
28 }
29
30 void
31 netutils_cleanup()
32 {
33 #ifdef WIN32
34 WSACleanup();
35 #endif
36 }
37
38 int
39 netutils_init_socket(unsigned short *port, int use_ipv6, int use_udp)
40 {
41 int family = use_ipv6 ? AF_INET6 : AF_INET;
42 int type = use_udp ? SOCK_DGRAM : SOCK_STREAM;
43 int proto = use_udp ? IPPROTO_UDP : IPPROTO_TCP;
44
45 struct sockaddr_storage saddr;
46 socklen_t socklen;
47 int server_fd;
48 int ret;
49
50 assert(port);
51
52 server_fd = socket(family, type, proto);
53 if (server_fd == -1) {
54 goto cleanup;
55 }
56
57 memset(&saddr, 0, sizeof(saddr));
58 if (use_ipv6) {
59 struct sockaddr_in6 *sin6ptr = (struct sockaddr_in6 *)&saddr;
60
61 /* Initialize sockaddr for bind */
62 sin6ptr->sin6_family = family;
63 sin6ptr->sin6_addr = in6addr_any;
64 sin6ptr->sin6_port = htons(*port);
65
66 socklen = sizeof(*sin6ptr);
67 ret = bind(server_fd, (struct sockaddr *)sin6ptr, socklen);
68 if (ret == -1) {
69 goto cleanup;
70 }
71
72 ret = getsockname(server_fd, (struct sockaddr *)sin6ptr, &socklen);
73 if (ret == -1) {
74 goto cleanup;
75 }
76 *port = ntohs(sin6ptr->sin6_port);
77 } else {
78 struct sockaddr_in *sinptr = (struct sockaddr_in *)&saddr;
79
80 /* Initialize sockaddr for bind */
81 sinptr->sin_family = family;
82 sinptr->sin_addr.s_addr = INADDR_ANY;
83 sinptr->sin_port = htons(*port);
84
85 socklen = sizeof(*sinptr);
86 ret = bind(server_fd, (struct sockaddr *)sinptr, socklen);
87 if (ret == -1) {
88 goto cleanup;
89 }
90
91 ret = getsockname(server_fd, (struct sockaddr *)sinptr, &socklen);
92 if (ret == -1) {
93 goto cleanup;
94 }
95 *port = ntohs(sinptr->sin_port);
96 }
97 return server_fd;
98
99 cleanup:
100 ret = SOCKET_GET_ERROR();
101 if (server_fd != -1) {
102 closesocket(server_fd);
103 }
104 SOCKET_SET_ERROR(ret);
105 return -1;
106 }
107
108 unsigned char *
109 netutils_get_address(void *sockaddr, int *length)
110 {
111 unsigned char ipv4_prefix[] = { 0,0,0,0,0,0,0,0,0,0,255,255 };
112 struct sockaddr *address = sockaddr;
113
114 assert(address);
115 assert(length);
116
117 if (address->sa_family == AF_INET) {
118 struct sockaddr_in *sin;
119
120 sin = (struct sockaddr_in *)address;
121 *length = sizeof(sin->sin_addr.s_addr);
122 return (unsigned char *)&sin->sin_addr.s_addr;
123 } else if (address->sa_family == AF_INET6) {
124 struct sockaddr_in6 *sin6;
125
126 sin6 = (struct sockaddr_in6 *)address;
127 if (!memcmp(sin6->sin6_addr.s6_addr, ipv4_prefix, 12)) {
128 /* Actually an embedded IPv4 address */
129 *length = sizeof(sin6->sin6_addr.s6_addr)-12;
130 return (sin6->sin6_addr.s6_addr+12);
131 }
132 *length = sizeof(sin6->sin6_addr.s6_addr);
133 return sin6->sin6_addr.s6_addr;
134 }
135
136 *length = 0;
137 return NULL;
138 }
139