Add some really ugly scons scripts to compile libraries
[deb_shairplay.git] / src / lib / netutils.c
CommitLineData
2340bcd3
JVH
1#include <stdlib.h>
2#include <string.h>
3#include <assert.h>
4
5#include "compat.h"
6
7int
8netutils_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
30void
31netutils_cleanup()
32{
33#ifdef WIN32
34 WSACleanup();
35#endif
36}
37
38int
39netutils_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
99cleanup:
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
108unsigned char *
109netutils_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