#include <netinet/in.h>
#include "libbb.h"
-static const int one = 1;
int setsockopt_reuseaddr(int fd)
{
- return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+ return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
}
int setsockopt_broadcast(int fd)
{
- return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one));
+ return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
}
void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
}
}
-/* Return network byte ordered port number for a service.
+/* Return port number for a service.
* If "port" is a number use it as the port.
* If "port" is a name it is looked up in /etc/services, if it isnt found return
* default_port */
port_nr = bb_strtou(port, NULL, 10);
if (errno || port_nr > 65535) {
struct servent *tserv = getservbyname(port, protocol);
+ port_nr = default_port;
if (tserv)
port_nr = ntohs(tserv->s_port);
}
/* "Old" networking API - only IPv4 */
-
+/*
void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
{
struct hostent *he;
memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
}
+
int xconnect_tcp_v4(struct sockaddr_in *s_addr)
{
int s = xsocket(AF_INET, SOCK_STREAM, 0);
xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));
return s;
}
-
+*/
/* "New" networking API */
-void set_port(len_and_sockaddr *lsa, unsigned port)
+int get_nport(len_and_sockaddr *lsa)
+{
+#if ENABLE_FEATURE_IPV6
+ if (lsa->sa.sa_family == AF_INET6) {
+ return lsa->sin6.sin6_port;
+ }
+#endif
+ if (lsa->sa.sa_family == AF_INET) {
+ return lsa->sin.sin_port;
+ }
+ /* What? UNIX socket? IPX?? :) */
+ return -1;
+}
+
+void set_nport(len_and_sockaddr *lsa, unsigned port)
{
#if ENABLE_FEATURE_IPV6
if (lsa->sa.sa_family == AF_INET6) {
/* What? UNIX socket? IPX?? :) */
}
-/* peer: "1.2.3.4[:port]", "www.google.com[:port]"
+/* host: "1.2.3.4[:port]", "www.google.com[:port]"
* port: if neither of above specifies port #
*/
static len_and_sockaddr* str2sockaddr(const char *host, int port, int ai_flags)
r = xmalloc(offsetof(len_and_sockaddr, sa) + result->ai_addrlen);
r->len = result->ai_addrlen;
memcpy(&r->sa, result->ai_addr, result->ai_addrlen);
- set_port(r, htons(port));
+ set_nport(r, htons(port));
freeaddrinfo(result);
return r;
}
return str2sockaddr(host, port, NI_NUMERICHOST);
}
-static int xsocket_stream(len_and_sockaddr *lsa)
+int xsocket_stream(len_and_sockaddr **lsap)
{
+ len_and_sockaddr *lsa;
int fd;
+ int len = sizeof(struct sockaddr_in);
+ int family = AF_INET;
+
#if ENABLE_FEATURE_IPV6
fd = socket(AF_INET6, SOCK_STREAM, 0);
- lsa->sa.sa_family = AF_INET6;
- lsa->len = sizeof(struct sockaddr_in6);
- if (fd >= 0)
- return fd;
+ if (fd >= 0) {
+ len = sizeof(struct sockaddr_in6);
+ family = AF_INET6;
+ } else
#endif
- fd = xsocket(AF_INET, SOCK_STREAM, 0);
- lsa->sa.sa_family = AF_INET;
- lsa->len = sizeof(struct sockaddr_in);
+ {
+ fd = xsocket(AF_INET, SOCK_STREAM, 0);
+ }
+ lsa = xzalloc(offsetof(len_and_sockaddr, sa) + len);
+ lsa->len = len;
+ lsa->sa.sa_family = family;
+ *lsap = lsa;
return fd;
}
/* user specified bind addr dictates family */
fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
} else {
- lsa = xzalloc(offsetof(len_and_sockaddr, sa) +
- USE_FEATURE_IPV6(sizeof(struct sockaddr_in6))
- SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in))
- );
- fd = xsocket_stream(lsa);
+ fd = xsocket_stream(&lsa);
+ set_nport(lsa, htons(port));
}
setsockopt_reuseaddr(fd);
xbind(fd, &lsa->sa, lsa->len);
return fd;
}
+/* We hijack this constant to mean something else */
+/* It doesn't hurt because we will add this bit anyway */
+#define IGNORE_PORT NI_NUMERICSERV
static char* sockaddr2str(const struct sockaddr *sa, socklen_t salen, int flags)
{
char host[128];
char serv[16];
int rc = getnameinfo(sa, salen,
host, sizeof(host),
+ /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
serv, sizeof(serv),
- flags | NI_NUMERICSERV /* do not resolve port# */
+ /* do not resolve port# into service _name_ */
+ flags | NI_NUMERICSERV
);
- if (rc) return NULL;
-// We probably need to use [%s]:%s for IPv6...
- return xasprintf("%s:%s", host, serv);
+ if (rc)
+ return NULL;
+ if (flags & IGNORE_PORT)
+ return xstrdup(host);
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET6) {
+ if (strchr(host, ':')) /* heh, it's not a resolved hostname */
+ return xasprintf("[%s]:%s", host, serv);
+ /*return xasprintf("%s:%s", host, serv);*/
+ /* - fall through instead */
+ }
+#endif
+ /* For now we don't support anything else, so it has to be INET */
+ /*if (sa->sa_family == AF_INET)*/
+ return xasprintf("%s:%s", host, serv);
+ /*return xstrdup(host);*/
}
char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen)
return sockaddr2str(sa, salen, 0);
}
+char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa, socklen_t salen)
+{
+ return sockaddr2str(sa, salen, NI_NAMEREQD | IGNORE_PORT);
+}
char* xmalloc_sockaddr2dotted(const struct sockaddr *sa, socklen_t salen)
{
return sockaddr2str(sa, salen, NI_NUMERICHOST);
}
+
+char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa, socklen_t salen)
+{
+ return sockaddr2str(sa, salen, NI_NUMERICHOST | IGNORE_PORT);
+}