1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
14 #include "socket-util.h"
16 int socket_address_parse(SocketAddress
*a
, const char *s
) {
25 a
->type
= SOCK_STREAM
;
28 /* IPv6 in [x:.....:z]:p notation */
30 if (!(e
= strchr(s
+1, ']')))
33 if (!(n
= strndup(s
+1, e
-s
-1)))
37 if (inet_pton(AF_INET6
, n
, &a
->sockaddr
.in6
.sin6_addr
) <= 0) {
39 return errno
!= 0 ? -errno
: -EINVAL
;
49 if ((r
= safe_atou(e
, &u
)) < 0)
52 if (u
<= 0 || u
> 0xFFFF)
55 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
56 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
57 a
->size
= sizeof(struct sockaddr_in6
);
59 } else if (*s
== '/') {
65 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
))
68 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
69 memcpy(a
->sockaddr
.un
.sun_path
, s
, l
);
70 a
->size
= sizeof(sa_family_t
) + l
+ 1;
72 } else if (*s
== '=') {
73 /* Abstract AF_UNIX socket */
77 if (l
>= sizeof(a
->sockaddr
.un
.sun_path
) - 1)
80 a
->sockaddr
.un
.sun_family
= AF_UNIX
;
81 memcpy(a
->sockaddr
.un
.sun_path
+1, s
+1, l
);
82 a
->size
= sizeof(struct sockaddr_un
);
86 if ((e
= strchr(s
, ':'))) {
89 if ((r
= safe_atou(e
+1, &u
)) < 0)
92 if (u
<= 0 || u
> 0xFFFF)
95 if (!(n
= strndup(s
, e
-s
)))
98 /* IPv4 in w.x.y.z:p notation? */
99 if ((r
= inet_pton(AF_INET
, n
, &a
->sockaddr
.in4
.sin_addr
)) < 0) {
105 /* Gotcha, it's a traditional IPv4 address */
108 a
->sockaddr
.in4
.sin_family
= AF_INET
;
109 a
->sockaddr
.in4
.sin_port
= htons((uint16_t) u
);
110 a
->size
= sizeof(struct sockaddr_in
);
114 /* Uh, our last resort, an interface name */
115 idx
= if_nametoindex(n
);
121 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
122 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
123 a
->sockaddr
.in6
.sin6_scope_id
= idx
;
124 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
125 a
->size
= sizeof(struct sockaddr_in6
);
130 if ((r
= safe_atou(s
, &u
)) < 0)
133 if (u
<= 0 || u
> 0xFFFF)
136 a
->sockaddr
.in6
.sin6_family
= AF_INET6
;
137 a
->sockaddr
.in6
.sin6_port
= htons((uint16_t) u
);
138 a
->sockaddr
.in6
.sin6_addr
= in6addr_any
;
139 a
->size
= sizeof(struct sockaddr_in6
);
146 int socket_address_verify(const SocketAddress
*a
) {
149 switch (socket_address_family(a
)) {
151 if (a
->size
!= sizeof(struct sockaddr_in
))
154 if (a
->sockaddr
.in4
.sin_port
== 0)
160 if (a
->size
!= sizeof(struct sockaddr_in6
))
163 if (a
->sockaddr
.in6
.sin6_port
== 0)
169 if (a
->size
< sizeof(sa_family_t
))
172 if (a
->size
> sizeof(sa_family_t
)) {
174 if (a
->sockaddr
.un
.sun_path
[0] == 0) {
176 if (a
->size
!= sizeof(struct sockaddr_un
))
182 if (!(e
= memchr(a
->sockaddr
.un
.sun_path
, 0, sizeof(a
->sockaddr
.un
.sun_path
))))
185 if (a
->size
!= sizeof(sa_family_t
) + (e
- a
->sockaddr
.un
.sun_path
) + 1)
193 return -EAFNOSUPPORT
;
197 int socket_address_print(const SocketAddress
*a
, char **p
) {
202 if ((r
= socket_address_verify(a
)) < 0)
205 switch (socket_address_family(a
)) {
209 if (!(ret
= new(char, INET_ADDRSTRLEN
+1+5+1)))
212 if (!inet_ntop(AF_INET
, &a
->sockaddr
.in4
.sin_addr
, ret
, INET_ADDRSTRLEN
)) {
217 sprintf(strchr(ret
, 0), ":%u", ntohs(a
->sockaddr
.in4
.sin_port
));
225 if (!(ret
= new(char, 1+INET6_ADDRSTRLEN
+2+5+1)))
229 if (!inet_ntop(AF_INET6
, &a
->sockaddr
.in6
.sin6_addr
, ret
+1, INET6_ADDRSTRLEN
)) {
234 sprintf(strchr(ret
, 0), "]:%u", ntohs(a
->sockaddr
.in6
.sin6_port
));
242 if (a
->size
<= sizeof(sa_family_t
)) {
244 if (!(ret
= strdup("<unamed>")))
247 } else if (a
->sockaddr
.un
.sun_path
[0] == 0) {
250 /* FIXME: We assume we can print the
251 * socket path here and that it hasn't
252 * more than one NUL byte. That is
253 * actually an invalid assumption */
255 if (!(ret
= new(char, sizeof(a
->sockaddr
.un
.sun_path
)+1)))
259 memcpy(ret
+1, a
->sockaddr
.un
.sun_path
+1, sizeof(a
->sockaddr
.un
.sun_path
)-1);
260 ret
[sizeof(a
->sockaddr
.un
.sun_path
)] = 0;
264 if (!(ret
= strdup(a
->sockaddr
.un
.sun_path
)))
277 int socket_address_listen(const SocketAddress
*a
, int backlog
, SocketAddressBindIPv6Only only
, int *ret
) {
282 if ((r
= socket_address_verify(a
)) < 0)
285 if ((fd
= socket(socket_address_family(a
), a
->type
| SOCK_NONBLOCK
| SOCK_CLOEXEC
, 0)) < 0)
288 if (socket_address_family(a
) == AF_INET6
&& only
!= SOCKET_ADDRESS_DEFAULT
) {
289 int flag
= only
== SOCKET_ADDRESS_IPV6_ONLY
;
291 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &flag
, sizeof(flag
)) < 0) {
297 if (bind(fd
, &a
->sockaddr
.sa
, a
->size
) < 0) {
302 if (a
->type
== SOCK_STREAM
)
303 if (listen(fd
, backlog
) < 0) {