#include <netinet/in.h>
#include <netdb.h>
#include <sys/signal.h>
-#include <printf.h>
#ifdef HAVE_LINUX_SOCKIOS_H
#include <linux/sockios.h>
#endif
/* Only for direct mode */
{CONF_VAR_IPV4, "visibleipv4", {.ipv4 = {0}}},
{CONF_VAR_STRING, "publicif", {.str = L""}},
+ /* Diffserv should be supported on IPv4, too, but I don't know the
+ * API to do that. */
+ {CONF_VAR_INT, "diffserv-mincost", {.num = 0}},
+ {CONF_VAR_INT, "diffserv-maxrel", {.num = 0}},
+ {CONF_VAR_INT, "diffserv-maxtp", {.num = 0}},
+ {CONF_VAR_INT, "diffserv-mindelay", {.num = 0}},
{CONF_VAR_END}
};
*lenbuf = sizeof(*ipv4);
return(0);
}
- if((pif = icwcstombs(confgetstr("net", "publicif"), NULL)) == NULL)
+ if((pif = icswcstombs(confgetstr("net", "publicif"), NULL, NULL)) == NULL)
{
flog(LOG_ERR, "could not convert net.publicif into local charset: %s", strerror(errno));
return(-1);
memcpy(ipv4, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
} else {
free(ipv4);
+ free(conf.ifc_buf);
+ close(sock);
flog(LOG_WARNING, "could not locate an unambiguous interface for determining your public IP address - set net.publicif");
errno = ENFILE; /* XXX: There's no appropriate one for this... */
return(-1);
}
}
}
+ free(conf.ifc_buf);
close(sock);
if(ipv4 != NULL)
{
}
}
+void sockpushdata(struct socket *sk, void *buf, size_t size)
+{
+ switch(sk->type)
+ {
+ case SOCK_STREAM:
+ sizebuf(&sk->inbuf.s.buf, &sk->inbuf.s.bufsize, sk->inbuf.s.datasize + size, 1, 1);
+ memmove(sk->inbuf.s.buf + size, sk->inbuf.s.buf, sk->inbuf.s.datasize);
+ memcpy(sk->inbuf.s.buf, buf, size);
+ sk->inbuf.s.datasize += size;
+ break;
+ case SOCK_DGRAM:
+ /* XXX */
+ break;
+ }
+ return;
+}
+
void *sockgetinbuf(struct socket *sk, size_t *size)
{
void *buf;
return(ret);
}
-struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
-{
- struct socket *sk;
- int intbuf;
-
- if(confgetint("net", "mode") == 1)
- {
- errno = EOPNOTSUPP;
- return(NULL);
- }
- /* I don't know if this is actually correct (it probably isn't),
- * but since, at on least Linux systems, PF_* are specifically
- * #define'd to their AF_* counterparts, it allows for a severely
- * smoother implementation. If it breaks something on your
- * platform, please tell me so.
- */
- if(confgetint("net", "mode") == 0)
- {
- if((sk = mksock(name->sa_family, type)) == NULL)
- return(NULL);
- sk->state = SOCK_LST;
- if(confgetint("net", "reuseaddr"))
- {
- intbuf = 1;
- setsockopt(sk->fd, SOL_SOCKET, SO_REUSEADDR, &intbuf, sizeof(intbuf));
- }
- if(bind(sk->fd, name, namelen) < 0)
- {
- putsock(sk);
- return(NULL);
- }
- if(listen(sk->fd, 16) < 0)
- {
- putsock(sk);
- return(NULL);
- }
- sk->acceptcb = func;
- sk->data = data;
- return(sk);
- }
- errno = EOPNOTSUPP;
- return(NULL);
-}
-
/*
* The difference between netcslisten() and netcslistenlocal() is that
* netcslistenlocal() always listens on the local host, instead of
struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
{
struct socket *sk;
+ int intbuf;
/* I don't know if this is actually correct (it probably isn't),
* but since, at on least Linux systems, PF_* are specifically
if((sk = mksock(name->sa_family, type)) == NULL)
return(NULL);
sk->state = SOCK_LST;
+ if(confgetint("net", "reuseaddr"))
+ {
+ intbuf = 1;
+ setsockopt(sk->fd, SOL_SOCKET, SO_REUSEADDR, &intbuf, sizeof(intbuf));
+ }
if(bind(sk->fd, name, namelen) < 0)
{
putsock(sk);
return(sk);
}
+struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
+{
+ if(confgetint("net", "mode") == 1)
+ {
+ errno = EOPNOTSUPP;
+ return(NULL);
+ }
+ if(confgetint("net", "mode") == 0)
+ return(netcslistenlocal(type, name, namelen, func, data));
+ errno = EOPNOTSUPP;
+ return(NULL);
+}
+
+struct socket *netcstcplisten(int port, int local, void (*func)(struct socket *, struct socket *, void *), void *data)
+{
+ struct sockaddr_in addr;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 addr6;
+#endif
+ struct socket *(*csfunc)(int, struct sockaddr *, socklen_t, void (*)(struct socket *, struct socket *, void *), void *);
+ struct socket *ret;
+
+ if(local)
+ csfunc = netcslistenlocal;
+ else
+ csfunc = netcslisten;
+#ifdef HAVE_IPV6
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = htons(port);
+ addr6.sin6_addr = in6addr_any;
+ if((ret = csfunc(SOCK_STREAM, (struct sockaddr *)&addr6, sizeof(addr6), func, data)) != NULL)
+ return(ret);
+ if((ret == NULL) && (errno != EAFNOSUPPORT))
+ return(NULL);
+#endif
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ return(csfunc(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), func, data));
+}
+
struct socket *netcsdgram(struct sockaddr *name, socklen_t namelen)
{
struct socket *sk;
int socksettos(struct socket *sk, int tos)
{
+ int buf;
+
if(sk->family == AF_INET)
{
- if(setsockopt(sk->fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
+ switch(tos)
+ {
+ case 0:
+ buf = 0;
+ break;
+ case SOCK_TOS_MINCOST:
+ buf = 0x02;
+ break;
+ case SOCK_TOS_MAXREL:
+ buf = 0x04;
+ break;
+ case SOCK_TOS_MAXTP:
+ buf = 0x08;
+ break;
+ case SOCK_TOS_MINDELAY:
+ buf = 0x10;
+ break;
+ default:
+ flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos);
+ return(-1);
+ }
+ if(setsockopt(sk->fd, SOL_IP, IP_TOS, &buf, sizeof(buf)) < 0)
{
flog(LOG_WARNING, "could not set sock TOS to %i: %s", tos, strerror(errno));
return(-1);
}
return(0);
}
- /* XXX: How does the IPv6 traffic class work? */
+ if(sk->family == AF_INET6)
+ {
+ switch(tos)
+ {
+ case 0:
+ buf = 0;
+ case SOCK_TOS_MINCOST:
+ buf = confgetint("net", "diffserv-mincost");
+ break;
+ case SOCK_TOS_MAXREL:
+ buf = confgetint("net", "diffserv-maxrel");
+ break;
+ case SOCK_TOS_MAXTP:
+ buf = confgetint("net", "diffserv-maxtp");
+ break;
+ case SOCK_TOS_MINDELAY:
+ buf = confgetint("net", "diffserv-mindelay");
+ break;
+ default:
+ flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos);
+ return(-1);
+ }
+ /*
+ On Linux, the API IPv6 flow label management doesn't seem to
+ be entirely complete, so I guess this will have to wait.
+
+ if(setsockopt(...) < 0)
+ {
+ flog(LOG_WARNING, "could not set sock traffic class to %i: %s", tos, strerror(errno));
+ return(-1);
+ }
+ */
+ return(0);
+ }
flog(LOG_WARNING, "could not set TOS on sock of family %i", sk->family);
return(1);
}
}
}
+int addreq(struct sockaddr *x, struct sockaddr *y)
+{
+ struct sockaddr_un *u1, *u2;
+ struct sockaddr_in *n1, *n2;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 *s1, *s2;
+#endif
+
+ if(x->sa_family != y->sa_family)
+ return(0);
+ switch(x->sa_family) {
+ case AF_UNIX:
+ u1 = (struct sockaddr_un *)x; u2 = (struct sockaddr_un *)y;
+ if(strncmp(u1->sun_path, u2->sun_path, sizeof(u1->sun_path)))
+ return(0);
+ break;
+ case AF_INET:
+ n1 = (struct sockaddr_in *)x; n2 = (struct sockaddr_in *)y;
+ if(n1->sin_port != n2->sin_port)
+ return(0);
+ if(n1->sin_addr.s_addr != n2->sin_addr.s_addr)
+ return(0);
+ break;
+ case AF_INET6:
+ s1 = (struct sockaddr_in6 *)x; s2 = (struct sockaddr_in6 *)y;
+ if(s1->sin6_port != s2->sin6_port)
+ return(0);
+ if(memcmp(s1->sin6_addr.s6_addr, s2->sin6_addr.s6_addr, sizeof(s1->sin6_addr.s6_addr)))
+ return(0);
+ break;
+ }
+ return(1);
+}
+
char *formataddress(struct sockaddr *arg, socklen_t arglen)
{
struct sockaddr_un *UNIX; /* Some wise guy has #defined unix with
ipv6 = (struct sockaddr_in6 *)arg;
if(inet_ntop(AF_INET6, &ipv6->sin6_addr, buf, sizeof(buf)) == NULL)
return(NULL);
- ret = sprintf2("%s:%i", buf, (int)ntohs(ipv6->sin6_port));
+ ret = sprintf2("[%s]:%i", buf, (int)ntohs(ipv6->sin6_port));
break;
#endif
default: