#include "network.h"
#include "tree234.h"
+#define ipv4_is_loopback(addr) \
+ ((ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)
+
struct Socket_tag {
struct socket_function_table *fn;
/* the above variable absolutely *must* be the first in this structure */
int sk_addrtype(SockAddr addr)
{
- return addr->family;
+ return (addr->family == AF_INET ? ADDRTYPE_IPV4 : ADDRTYPE_IPV6);
}
void sk_addrcopy(SockAddr addr, char *buf)
#endif
struct in_addr a;
a.s_addr = htonl(addr->address);
- strncpy(buf, (char*) &a.s_addr, 4);
+ memcpy(buf, (char*) &a.s_addr, 4);
#ifdef IPV6
} else {
- strncpy(buf, (char*) addr->ai, 16);
+ memcpy(buf, (char*) addr->ai, 16);
}
#endif
}
return (Socket) ret;
}
-Socket sk_newlistener(int port, Plug plug, int local_host_only)
+Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
{
static struct socket_function_table fn_table = {
sk_tcp_plug,
if (addr->family == AF_INET6) {
memset(&a6, 0, sizeof(a6));
a6.sin6_family = AF_INET6;
+ /* FIXME: srcaddr is ignored for IPv6, because I (SGT) don't
+ * know how to do it. :-) */
if (local_host_only)
a6.sin6_addr = in6addr_loopback;
else
} else
#endif
{
+ int got_addr = 0;
a.sin_family = AF_INET;
- if (local_host_only)
- a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- else
- a.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ /*
+ * Bind to source address. First try an explicitly
+ * specified one...
+ */
+ if (srcaddr) {
+ a.sin_addr.s_addr = inet_addr(srcaddr);
+ if (a.sin_addr.s_addr != INADDR_NONE) {
+ /* Override localhost_only with specified listen addr. */
+ ret->localhost_only = ipv4_is_loopback(a.sin_addr);
+ got_addr = 1;
+ }
+ }
+
+ /*
+ * ... and failing that, go with one of the standard ones.
+ */
+ if (!got_addr) {
+ if (local_host_only)
+ a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ else
+ a.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+
a.sin_port = htons((short)port);
}
#ifdef IPV6
s->pending_error = err;
return;
} else {
- logevent(winsock_error_string(err));
+ /* We're inside the Windows frontend here, so we know
+ * that the frontend handle is unnecessary. */
+ logevent(NULL, winsock_error_string(err));
fatalbox("%s", winsock_error_string(err));
}
} else {
u_long atmark;
/* wParam is the socket itself */
+
+ /*
+ * One user has reported an assertion failure in tree234 which
+ * indicates a null element pointer has been passed to a
+ * find*234 function. The following find234 is the only one in
+ * the whole program that I can see being capable of doing
+ * this, hence I'm forced to conclude that WinSock is capable
+ * of sending me netevent messages with wParam==0. I want to
+ * know what the rest of the message is if it does so!
+ */
+ if (wParam == 0) {
+ char *str;
+ str = dupprintf("Strange WinSock message: wp=%08x lp=%08x",
+ (int)wParam, (int)lParam);
+ logevent(NULL, str);
+ connection_fatal(NULL, str);
+ sfree(str);
+ }
+
s = find234(sktree, (void *) wParam, cmpforsearch);
if (!s)
return 1; /* boggle */
if (ret <= 0) {
char *str = (ret == 0 ? "Internal networking trouble" :
winsock_error_string(WSAGetLastError()));
- logevent(str);
+ /* We're inside the Windows frontend here, so we know
+ * that the frontend handle is unnecessary. */
+ logevent(NULL, str);
fatalbox("%s", str);
} else {
return plug_receive(s->plug, 2, buf, ret);
break;
}
- if (s->localhost_only &&
- ntohl(isa.sin_addr.s_addr) != INADDR_LOOPBACK) {
+ if (s->localhost_only && !ipv4_is_loopback(isa.sin_addr)) {
closesocket(t); /* dodgy WinSock let nonlocal through */
} else if (plug_accepting(s->plug, (void*)t)) {
closesocket(t); /* denied or error */
Actual_Socket s = index234(sktree, (*state)++);
return s ? s->s : INVALID_SOCKET;
}
+
+int net_service_lookup(char *service)
+{
+ struct servent *se;
+ se = getservbyname(service, NULL);
+ if (se != NULL)
+ return ntohs(se->s_port);
+ else
+ return 0;
+}