* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*
- * $Id: commio.c 26254 2008-12-10 04:04:38Z androsyn $
*/
+
#include <librb_config.h>
#include <rb_lib.h>
#include <commio-int.h>
static PF rb_connect_timeout;
static PF rb_connect_tryconnect;
-#ifdef RB_IPV6
static void mangle_mapped_sockaddr(struct sockaddr *in);
-#endif
#ifndef HAVE_SOCKETPAIR
static int rb_inet_socketpair(int d, int type, int protocol, rb_platform_fd_t sv[2]);
RB_DLINK_FOREACH_SAFE(ptr, next, closed_list.head)
{
F = ptr->data;
+
+ number_fd--;
+
+#ifdef _WIN32
+ if(F->type & (RB_FD_SOCKET | RB_FD_PIPE))
+ closesocket(F->fd);
+ else
+#endif
+ close(F->fd);
+
rb_dlinkDelete(ptr, &closed_list);
rb_bh_free(fd_heap, F);
}
{
struct rb_sockaddr_storage st;
rb_fde_t *new_F;
- rb_socklen_t addrlen = sizeof(st);
+ rb_socklen_t addrlen;
int new_fd;
while(1)
{
+ memset(&st, 0, sizeof(st));
+ addrlen = sizeof(st);
+
new_fd = accept(F->fd, (struct sockaddr *)&st, &addrlen);
rb_get_errno();
if(new_fd < 0)
rb_close(new_F);
}
-#ifdef RB_IPV6
mangle_mapped_sockaddr((struct sockaddr *)&st);
-#endif
if(F->accept->precb != NULL)
{
/*
* void rb_connect_tcp(rb_platform_fd_t fd, struct sockaddr *dest,
- * struct sockaddr *clocal, int socklen,
+ * struct sockaddr *clocal,
* CNCB *callback, void *data, int timeout)
* Input: An fd to connect with, a host and port to connect to,
- * a local sockaddr to connect from + length(or NULL to use the
+ * a local sockaddr to connect from (or NULL to use the
* default), a callback, the data to pass into the callback, the
* address family.
* Output: None.
*/
void
rb_connect_tcp(rb_fde_t *F, struct sockaddr *dest,
- struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
+ struct sockaddr *clocal, CNCB * callback, void *data, int timeout)
{
if(F == NULL)
return;
* virtual host IP, for completeness.
* -- adrian
*/
- if((clocal != NULL) && (bind(F->fd, clocal, socklen) < 0))
+ if((clocal != NULL) && (bind(F->fd, clocal, GET_SS_LEN(clocal)) < 0))
{
/* Failure, call the callback with RB_ERR_BIND */
rb_connect_callback(F, RB_ERR_BIND);
if(rb_unlikely(fd < 0))
return NULL; /* errno will be passed through, yay.. */
-#if defined(RB_IPV6) && defined(IPV6_V6ONLY)
/*
* Make sure we can take both IPv4 and IPv6 connections
* on an AF_INET6 socket
if(family == AF_INET6)
{
int off = 1;
- if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)) == -1)
+ if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &off, sizeof(off)) == -1)
{
rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to 1 on FD %d: %s",
fd, strerror(errno));
return NULL;
}
}
-#endif
F = rb_open(fd, RB_FD_SOCKET, note);
if(F == NULL)
* If a sockaddr_storage is AF_INET6 but is a mapped IPv4
* socket manged the sockaddr.
*/
-#ifdef RB_IPV6
static void
mangle_mapped_sockaddr(struct sockaddr *in)
{
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)in;
- if(in->sa_family == AF_INET)
- return;
-
if(in->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr))
{
struct sockaddr_in in4;
in4.sin_addr.s_addr = ((uint32_t *)&in6->sin6_addr)[3];
memcpy(in, &in4, sizeof(struct sockaddr_in));
}
- return;
}
-#endif
/*
* rb_listen() - listen on a port
ClearFDOpen(F);
}
- number_fd--;
-
-#ifdef _WIN32
- if(type & (RB_FD_SOCKET | RB_FD_PIPE))
- {
- closesocket(fd);
- return;
- }
- else
-#endif
- close(fd);
+ if(type & RB_FD_LISTEN)
+ shutdown(fd, SHUT_RDWR);
}
return 0;
}
-int
+rb_platform_fd_t
rb_get_fd(rb_fde_t *F)
{
if(F == NULL)
*/
static const char *inet_ntop4(const unsigned char *src, char *dst, unsigned int size);
-#ifdef RB_IPV6
static const char *inet_ntop6(const unsigned char *src, char *dst, unsigned int size);
-#endif
/* const char *
* inet_ntop4(src, dst, size)
* author:
* Paul Vixie, 1996.
*/
-#ifdef RB_IPV6
static const char *
inet_ntop6(const unsigned char *src, char *dst, unsigned int size)
{
}
return memcpy(dst, tmp, tp - tmp);
}
-#endif
int
rb_inet_pton_sock(const char *src, struct sockaddr *dst)
{
if(rb_inet_pton(AF_INET, src, &((struct sockaddr_in *)dst)->sin_addr))
{
- ((struct sockaddr_in *)dst)->sin_port = 0;
- ((struct sockaddr_in *)dst)->sin_family = AF_INET;
+ SET_SS_FAMILY(dst, AF_INET);
+ SET_SS_PORT(dst, 0);
SET_SS_LEN(dst, sizeof(struct sockaddr_in));
return 1;
}
-#ifdef RB_IPV6
else if(rb_inet_pton(AF_INET6, src, &((struct sockaddr_in6 *)dst)->sin6_addr))
{
- ((struct sockaddr_in6 *)dst)->sin6_port = 0;
- ((struct sockaddr_in6 *)dst)->sin6_family = AF_INET6;
+ SET_SS_FAMILY(dst, AF_INET6);
+ SET_SS_PORT(dst, 0);
SET_SS_LEN(dst, sizeof(struct sockaddr_in6));
return 1;
}
-#endif
return 0;
}
{
case AF_INET:
return (rb_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, dst, size));
- break;
-#ifdef RB_IPV6
case AF_INET6:
return (rb_inet_ntop
(AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr, dst, size));
- break;
-#endif
default:
return NULL;
- break;
}
}
{
case AF_INET:
return (inet_ntop4(src, dst, size));
-#ifdef RB_IPV6
case AF_INET6:
if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src) ||
IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src))
s6_addr[12], dst, size));
else
return (inet_ntop6(src, dst, size));
-
-
-#endif
default:
return (NULL);
}
return (1);
}
-#ifdef RB_IPV6
/* int
* inet_pton6(src, dst)
* convert presentation level address to network order binary form.
memcpy(dst, tmp, IN6ADDRSZ);
return (1);
}
-#endif
+
int
rb_inet_pton(int af, const char *src, void *dst)
{
{
case AF_INET:
return (inet_pton4(src, dst));
-#ifdef RB_IPV6
case AF_INET6:
/* Somebody might have passed as an IPv4 address this is sick but it works */
if(inet_pton4(src, dst))
}
else
return (inet_pton6(src, dst));
-#endif
default:
return (-1);
}
}
-
int
rb_ignore_errno(int error)
{
if(count > 0)
{
+ size_t ucount = (size_t)count;
int len = CMSG_SPACE(sizeof(int) * count);
char buf[len];
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * count);
- for(unsigned int i = 0; i < count; i++)
+ for(size_t i = 0; i < ucount; i++)
{
((int *)CMSG_DATA(cmsg))[i] = rb_get_fd(F[i]);
}
}
return sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
}
-#else
+#else /* defined(HAVE_SENDMSG) && !defined(WIN32) */
#ifndef _WIN32
int
rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
errno = ENOSYS;
return -1;
}
-#endif
-#endif
+#endif /* _WIN32 */
+#endif /* defined(HAVE_SENDMSG) && !defined(WIN32) */
+
+int
+rb_ipv4_from_ipv6(const struct sockaddr_in6 *restrict ip6, struct sockaddr_in *restrict ip4)
+{
+ int i;
+
+ if (!memcmp(ip6->sin6_addr.s6_addr, "\x20\x02", 2))
+ {
+ /* 6to4 and similar */
+ memcpy(&ip4->sin_addr, ip6->sin6_addr.s6_addr + 2, 4);
+ }
+ else if (!memcmp(ip6->sin6_addr.s6_addr, "\x20\x01\x00\x00", 4))
+ {
+ /* Teredo */
+ for (i = 0; i < 4; i++)
+ ((uint8_t *)&ip4->sin_addr)[i] = 0xFF ^
+ ip6->sin6_addr.s6_addr[12 + i];
+ }
+ else
+ return 0;
+ SET_SS_LEN(ip4, sizeof(struct sockaddr_in));
+ ip4->sin_family = AF_INET;
+ ip4->sin_port = 0;
+ return 1;
+}