struct SockAddr_tag {
char *error;
- /* address family this belongs to, AF_INET for IPv4, AF_INET6 for IPv6. */
+ /*
+ * Which address family this address belongs to. AF_INET for
+ * IPv4; AF_INET6 for IPv6; AF_UNSPEC indicates that name
+ * resolution has not been done and a simple host name is held
+ * in this SockAddr structure.
+ */
int family;
unsigned long address; /* Address IPv4 style. */
#ifdef IPV6
struct addrinfo *ai; /* Address IPv6 style. */
#endif
+ char hostname[512]; /* Store an unresolved host name. */
};
static tree234 *sktree;
+static void uxsel_tell(Actual_Socket s);
+
static int cmpfortree(void *av, void *bv)
{
Actual_Socket a = (Actual_Socket) av, b = (Actual_Socket) bv;
return strerror(error);
}
-SockAddr sk_namelookup(char *host, char **canonicalname)
+SockAddr sk_namelookup(const char *host, char **canonicalname)
{
- SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
+ SockAddr ret = snew(struct SockAddr_tag);
unsigned long a;
struct hostent *h = NULL;
char realhost[8192];
}
ret->address = ntohl(a);
realhost[lenof(realhost)-1] = '\0';
- *canonicalname = smalloc(1+strlen(realhost));
+ *canonicalname = snewn(1+strlen(realhost), char);
strcpy(*canonicalname, realhost);
return ret;
}
+SockAddr sk_nonamelookup(const char *host)
+{
+ SockAddr ret = snew(struct SockAddr_tag);
+ ret->error = NULL;
+ ret->family = AF_UNSPEC;
+ strncpy(ret->hostname, host, lenof(ret->hostname));
+ ret->hostname[lenof(ret->hostname)-1] = '\0';
+ return ret;
+}
+
void sk_getaddr(SockAddr addr, char *buf, int buflen)
{
#ifdef IPV6
- if (addr->family == AF_INET) {
+ if (addr->family == AF_INET6) {
+ FIXME; /* I don't know how to get a text form of an IPv6 address. */
+ } else
#endif
+ if (addr->family == AF_INET) {
struct in_addr a;
a.s_addr = htonl(addr->address);
strncpy(buf, inet_ntoa(a), buflen);
-#ifdef IPV6
+ buf[buflen-1] = '\0';
} else {
- FIXME; /* I don't know how to get a text form of an IPv6 address. */
+ assert(addr->family == AF_UNSPEC);
+ strncpy(buf, addr->hostname, buflen);
+ buf[buflen-1] = '\0';
}
+}
+
+int sk_hostname_is_local(char *name)
+{
+ return !strcmp(name, "localhost");
+}
+
+int sk_address_is_local(SockAddr addr)
+{
+#ifdef IPV6
+ if (addr->family == AF_INET6) {
+ FIXME; /* someone who can compile for IPV6 had better do this bit */
+ } else
#endif
+ if (addr->family == AF_INET) {
+ struct in_addr a;
+ a.s_addr = htonl(addr->address);
+ return ipv4_is_loopback(a);
+ } else {
+ assert(addr->family == AF_UNSPEC);
+ return 0; /* we don't know; assume not */
+ }
}
int sk_addrtype(SockAddr addr)
{
- return (addr->family == AF_INET ? ADDRTYPE_IPV4 : ADDRTYPE_IPV6);
+ return (addr->family == AF_INET ? ADDRTYPE_IPV4 :
+#ifdef IPV6
+ addr->family == AF_INET6 ? ADDRTYPE_IPV6 :
+#endif
+ ADDRTYPE_NAME);
}
void sk_addrcopy(SockAddr addr, char *buf)
{
+ assert(addr->family != AF_UNSPEC);
#ifdef IPV6
- if (addr->family == AF_INET) {
+ if (addr->family == AF_INET6) {
+ memcpy(buf, (char*) addr->ai, 16);
+ } else
#endif
+ if (addr->family == AF_INET) {
struct in_addr a;
a.s_addr = htonl(addr->address);
memcpy(buf, (char*) &a.s_addr, 4);
-#ifdef IPV6
- } else {
- memcpy(buf, (char*) addr->ai, 16);
}
-#endif
}
void sk_addr_free(SockAddr addr)
}
static void sk_tcp_close(Socket s);
-static int sk_tcp_write(Socket s, char *data, int len);
-static int sk_tcp_write_oob(Socket s, char *data, int len);
+static int sk_tcp_write(Socket s, const char *data, int len);
+static int sk_tcp_write_oob(Socket s, const char *data, int len);
static void sk_tcp_set_private_ptr(Socket s, void *ptr);
static void *sk_tcp_get_private_ptr(Socket s);
static void sk_tcp_set_frozen(Socket s, int is_frozen);
static char *sk_tcp_socket_error(Socket s);
+static struct socket_function_table tcp_fn_table = {
+ sk_tcp_plug,
+ sk_tcp_close,
+ sk_tcp_write,
+ sk_tcp_write_oob,
+ sk_tcp_flush,
+ sk_tcp_set_private_ptr,
+ sk_tcp_get_private_ptr,
+ sk_tcp_set_frozen,
+ sk_tcp_socket_error
+};
+
Socket sk_register(void *sock, Plug plug)
{
- static struct socket_function_table fn_table = {
- sk_tcp_plug,
- sk_tcp_close,
- sk_tcp_write,
- sk_tcp_write_oob,
- sk_tcp_flush,
- sk_tcp_set_private_ptr,
- sk_tcp_get_private_ptr,
- sk_tcp_set_frozen,
- sk_tcp_socket_error
- };
-
Actual_Socket ret;
/*
* Create Socket structure.
*/
- ret = smalloc(sizeof(struct Socket_tag));
- ret->fn = &fn_table;
+ ret = snew(struct Socket_tag);
+ ret->fn = &tcp_fn_table;
ret->error = NULL;
ret->plug = plug;
bufchain_init(&ret->output_data);
ret->oobinline = 0;
+ uxsel_tell(ret);
add234(sktree, ret);
return (Socket) ret;
Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
int nodelay, Plug plug)
{
- static struct socket_function_table fn_table = {
- sk_tcp_plug,
- sk_tcp_close,
- sk_tcp_write,
- sk_tcp_write_oob,
- sk_tcp_flush,
- sk_tcp_set_private_ptr,
- sk_tcp_get_private_ptr,
- sk_tcp_set_frozen,
- sk_tcp_socket_error
- };
-
int s;
#ifdef IPV6
struct sockaddr_in6 a6;
/*
* Create Socket structure.
*/
- ret = smalloc(sizeof(struct Socket_tag));
- ret->fn = &fn_table;
+ ret = snew(struct Socket_tag);
+ ret->fn = &tcp_fn_table;
ret->error = NULL;
ret->plug = plug;
bufchain_init(&ret->output_data);
/*
* Open socket.
*/
+ assert(addr->family != AF_UNSPEC);
s = socket(addr->family, SOCK_STREAM, 0);
ret->s = s;
a.sin_port = htons((short) port);
}
+ {
+ int i = 1;
+ ioctl(s, FIONBIO, &i);
+ }
+
if ((
#ifdef IPV6
connect(s, ((addr->family == AF_INET6) ?
connect(s, (struct sockaddr *) &a, sizeof(a))
#endif
) < 0) {
- /*
- * FIXME: We are prepared to receive EWOULDBLOCK here,
- * because we might want the connection to be made
- * asynchronously; but how do we actually arrange this in
- * Unix? I forget.
- */
- if ( errno != EWOULDBLOCK ) {
+ if ( errno != EINPROGRESS ) {
ret->error = error_string(errno);
return (Socket) ret;
}
ret->writable = 1;
}
+ uxsel_tell(ret);
add234(sktree, ret);
return (Socket) ret;
Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
{
- static struct socket_function_table fn_table = {
- sk_tcp_plug,
- sk_tcp_close,
- sk_tcp_write,
- sk_tcp_write_oob,
- sk_tcp_flush,
- sk_tcp_set_private_ptr,
- sk_tcp_get_private_ptr,
- sk_tcp_set_frozen,
- sk_tcp_socket_error
- };
-
int s;
#ifdef IPV6
struct sockaddr_in6 a6;
/*
* Create Socket structure.
*/
- ret = smalloc(sizeof(struct Socket_tag));
- ret->fn = &fn_table;
+ ret = snew(struct Socket_tag);
+ ret->fn = &tcp_fn_table;
ret->error = NULL;
ret->plug = plug;
bufchain_init(&ret->output_data);
return (Socket) ret;
}
+ uxsel_tell(ret);
add234(sktree, ret);
return (Socket) ret;
{
Actual_Socket s = (Actual_Socket) sock;
+ uxsel_del(s->s);
del234(sktree, s);
close(s->s);
sfree(s);
}
+int sk_getxdmdata(void *sock, unsigned long *ip, int *port)
+{
+ Actual_Socket s = (Actual_Socket) sock;
+ struct sockaddr_in addr;
+ socklen_t addrlen;
+
+ /*
+ * We must check that this socket really _is_ an Actual_Socket.
+ */
+ if (s->fn != &tcp_fn_table)
+ return 0; /* failure */
+
+ /*
+ * If we ever implement connecting to a local X server through
+ * a Unix socket, we return 0xFFFFFFFF for the IP address and
+ * our current pid for the port. Bizarre, but such is life.
+ */
+
+ addrlen = sizeof(addr);
+ if (getsockname(s->s, (struct sockaddr *)&addr, &addrlen) < 0 ||
+ addr.sin_family != AF_INET)
+ return 0;
+
+ *ip = ntohl(addr.sin_addr.s_addr);
+ *port = ntohs(addr.sin_port);
+
+ return 1;
+}
+
/*
* The function which tries to send on a socket once it's deemed
* writable.
}
}
}
+ uxsel_tell(s);
}
-static int sk_tcp_write(Socket sock, char *buf, int len)
+static int sk_tcp_write(Socket sock, const char *buf, int len)
{
Actual_Socket s = (Actual_Socket) sock;
return bufchain_size(&s->output_data);
}
-static int sk_tcp_write_oob(Socket sock, char *buf, int len)
+static int sk_tcp_write_oob(Socket sock, const char *buf, int len)
{
Actual_Socket s = (Actual_Socket) sock;
return s->sending_oob;
}
-int select_result(int fd, int event)
+static int net_select_result(int fd, int event)
{
int ret;
int err;
noise_ultralight(event);
switch (event) {
-#ifdef FIXME_NONBLOCKING_CONNECTIONS
- case FIXME: /* connected */
- s->connected = s->writable = 1;
- break;
-#endif
case 4: /* exceptional */
if (!s->oobinline) {
/*
}
break;
case 2: /* writable */
- {
+ if (!s->connected) {
+ /*
+ * select() reports a socket as _writable_ when an
+ * asynchronous connection is completed.
+ */
+ s->connected = s->writable = 1;
+ uxsel_tell(s);
+ break;
+ } else {
int bufsize_before, bufsize_after;
s->writable = 1;
bufsize_before = s->sending_oob + bufchain_size(&s->output_data);
recv(s->s, &c, 1, MSG_PEEK);
}
s->frozen_readable = 0;
+ uxsel_tell(s);
}
-/*
- * For Unix select()-based frontends: enumerate all sockets
- * currently active, and state whether we currently wish to receive
- * select events on them for reading, writing and exceptional
- * status.
- */
-static void set_rwx(Actual_Socket s, int *rwx)
+static void uxsel_tell(Actual_Socket s)
{
- int val = 0;
+ int rwx = 0;
+ if (!s->connected)
+ rwx |= 2; /* write == connect */
if (s->connected && !s->frozen)
- val |= 1 | 4; /* read, except */
+ rwx |= 1 | 4; /* read, except */
if (bufchain_size(&s->output_data))
- val |= 2; /* write */
+ rwx |= 2; /* write */
if (s->listener)
- val |= 1; /* read == accept */
- *rwx = val;
-}
-
-int first_socket(int *state, int *rwx)
-{
- Actual_Socket s;
- *state = 0;
- s = index234(sktree, (*state)++);
- if (s)
- set_rwx(s, rwx);
- return s ? s->s : -1;
-}
-
-int next_socket(int *state, int *rwx)
-{
- Actual_Socket s = index234(sktree, (*state)++);
- if (s)
- set_rwx(s, rwx);
- return s ? s->s : -1;
+ rwx |= 1; /* read == accept */
+ uxsel_set(s->s, rwx, net_select_result);
}
int net_service_lookup(char *service)