xsock_t comm_connect_unix(const char* path, int is_blocking) { xsock_t sock; struct sockaddr_un s_un; comm_init(); if (comm_unix_setup(&s_un, path) == -1) return (XORP_BAD_SOCKET); sock = comm_sock_open(s_un.sun_family, SOCK_STREAM, 0, is_blocking); if (sock == XORP_BAD_SOCKET) return (XORP_BAD_SOCKET); if (connect(sock, (struct sockaddr*) &s_un, sizeof(s_un)) == -1) { _comm_set_serrno(); if (is_blocking || comm_get_last_error() != EINPROGRESS) { XLOG_ERROR("Error connecting to unix socket. Path: %s. Error: %s", s_un.sun_path, comm_get_error_str(comm_get_last_error())); comm_sock_close(sock); return (XORP_BAD_SOCKET); } } return (sock); }
int comm_set_multicast_ttl(xsock_t sock, int val) { int family = comm_sock_get_family(sock); switch (family) { case AF_INET: { /* XXX: Most platforms now use int for this option; * legacy BSD specified u_char. */ u_char ip_multicast_ttl = val; if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, XORP_SOCKOPT_CAST(&ip_multicast_ttl), sizeof(ip_multicast_ttl)) < 0) { _comm_set_serrno(); XLOG_ERROR("setsockopt IP_MULTICAST_TTL %u: %s", ip_multicast_ttl, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } break; } #ifdef HAVE_IPV6 case AF_INET6: { int ip_multicast_ttl = val; if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, XORP_SOCKOPT_CAST(&ip_multicast_ttl), sizeof(ip_multicast_ttl)) < 0) { _comm_set_serrno(); XLOG_ERROR("setsockopt IPV6_MULTICAST_HOPS %u: %s", ip_multicast_ttl, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } break; } #endif /* HAVE_IPV6 */ default: XLOG_FATAL("Error %s setsockopt IP_MULTICAST_TTL/IPV6_MULTICAST_HOPS " "on socket %d: invalid family = %d", (val)? "set": "reset", sock, family); return (XORP_ERROR); } return (XORP_OK); }
int comm_set_receive_broadcast(xsock_t sock, int val) { #if defined(HOST_OS_WINDOWS) && defined(IP_RECEIVE_BROADCAST) /* * With Windows Server 2003 and later, you have to explicitly * ask to receive broadcast packets. */ DWORD ip_rx_bcast = (DWORD)val; if (setsockopt(sock, IPPROTO_IP, IP_RECEIVE_BROADCAST, XORP_SOCKOPT_CAST(&ip_rx_bcast), sizeof(ip_rx_bcast)) < 0) { _comm_set_serrno(); XLOG_ERROR("Error %s IP_RECEIVE_BROADCAST on socket %d: %s", (val)? "set": "reset", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else UNUSED(sock); UNUSED(val); return (XORP_OK); #endif }
int comm_set_linger(xsock_t sock, int enabled, int secs) { #ifdef SO_LINGER struct linger l; l.l_onoff = enabled; l.l_linger = secs; if (setsockopt(sock, SOL_SOCKET, SO_LINGER, XORP_SOCKOPT_CAST(&l), sizeof(l)) < 0) { _comm_set_serrno(); XLOG_ERROR("Error %s SO_LINGER %ds on socket %d: %s", (enabled)? "set": "reset", secs, sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else /* ! SO_LINGER */ UNUSED(sock); UNUSED(enabled); UNUSED(secs); XLOG_WARNING("SO_LINGER Undefined!"); return (XORP_ERROR); #endif /* ! SO_LINGER */ }
int comm_set_onesbcast(xsock_t sock, int enabled) { #ifdef IP_ONESBCAST int family = comm_sock_get_family(sock); if (family != AF_INET) { XLOG_ERROR("Invalid family of socket %d: family = %d (expected %d)", sock, family, AF_INET); return (XORP_ERROR); } if (setsockopt(sock, IPPROTO_IP, IP_ONESBCAST, XORP_SOCKOPT_CAST(&enabled), sizeof(enabled)) < 0) { _comm_set_serrno(); XLOG_ERROR("setsockopt IP_ONESBCAST %d: %s", enabled, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else /* ! IP_ONESBCAST */ XLOG_ERROR("setsockopt IP_ONESBCAST %u: %s", enabled, "IP_ONESBCAST support not present."); UNUSED(sock); UNUSED(enabled); return (XORP_ERROR); #endif /* ! IP_ONESBCAST */ }
int comm_set_iface6(xsock_t sock, unsigned int my_ifindex) { #ifdef HAVE_IPV6 int family = comm_sock_get_family(sock); if (family != AF_INET6) { XLOG_ERROR("Invalid family of socket %d: family = %d (expected %d)", sock, family, AF_INET6); return (XORP_ERROR); } if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, XORP_SOCKOPT_CAST(&my_ifindex), sizeof(my_ifindex)) < 0) { _comm_set_serrno(); XLOG_ERROR("setsockopt IPV6_MULTICAST_IF for interface index %d: %s", my_ifindex, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else /* ! HAVE_IPV6 */ comm_sock_no_ipv6("comm_set_iface6", sock, my_ifindex); return (XORP_ERROR); #endif /* ! HAVE_IPV6 */ }
int comm_set_iface4(xsock_t sock, const struct in_addr *in_addr) { int family = comm_sock_get_family(sock); struct in_addr my_addr; if (family != AF_INET) { XLOG_ERROR("Invalid family of socket %d: family = %d (expected %d)", sock, family, AF_INET); return (XORP_ERROR); } if (in_addr != NULL) my_addr.s_addr = in_addr->s_addr; else my_addr.s_addr = INADDR_ANY; if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, XORP_SOCKOPT_CAST(&my_addr), sizeof(my_addr)) < 0) { _comm_set_serrno(); XLOG_ERROR("setsockopt IP_MULTICAST_IF %s: %s", (in_addr)? inet_ntoa(my_addr) : "ANY", comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); }
int comm_sock_set_blocking(xsock_t sock, int is_blocking) { #ifdef HOST_OS_WINDOWS u_long opt; int flags; if (is_blocking) opt = 0; else opt = 1; flags = ioctlsocket(sock, FIONBIO, &opt); if (flags != 0) { _comm_set_serrno(); XLOG_ERROR("FIONBIO error: %s", comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } #else /* ! HOST_OS_WINDOWS */ int flags; if ( (flags = fcntl(sock, F_GETFL, 0)) < 0) { _comm_set_serrno(); XLOG_ERROR("F_GETFL error: %s", comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } if (is_blocking) flags &= ~O_NONBLOCK; else flags |= O_NONBLOCK; if (fcntl(sock, F_SETFL, flags) < 0) { _comm_set_serrno(); XLOG_ERROR("F_SETFL error: %s", comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } #endif /* ! HOST_OS_WINDOWS */ return (XORP_OK); }
int comm_set_loopback(xsock_t sock, int val) { int family = comm_sock_get_family(sock); switch (family) { case AF_INET: { u_char loop = val; if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, XORP_SOCKOPT_CAST(&loop), sizeof(loop)) < 0) { _comm_set_serrno(); XLOG_ERROR("setsockopt IP_MULTICAST_LOOP %u: %s", loop, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } break; } #ifdef HAVE_IPV6 case AF_INET6: { unsigned int loop6 = val; if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, XORP_SOCKOPT_CAST(&loop6), sizeof(loop6)) < 0) { _comm_set_serrno(); XLOG_ERROR("setsockopt IPV6_MULTICAST_LOOP %u: %s", loop6, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } break; } #endif /* HAVE_IPV6 */ default: XLOG_FATAL("Error %s setsockopt IP_MULTICAST_LOOP/IPV6_MULTICAST_LOOP " "on socket %d: invalid family = %d", (val)? "set": "reset", sock, family); return (XORP_ERROR); } return (XORP_OK); }
int comm_sock_get_family(xsock_t sock) { #ifdef HOST_OS_WINDOWS WSAPROTOCOL_INFO wspinfo; int err, len; len = sizeof(wspinfo); err = getsockopt(sock, SOL_SOCKET, SO_PROTOCOL_INFO, XORP_SOCKOPT_CAST(&wspinfo), &len); if (err != 0) { _comm_set_serrno(); XLOG_ERROR("Error getsockopt(SO_PROTOCOL_INFO) for socket %d: %s", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return ((int)wspinfo.iAddressFamily); #else /* ! HOST_OS_WINDOWS */ /* XXX: Should use struct sockaddr_storage. */ #ifndef MAXSOCKADDR #define MAXSOCKADDR 128 /* max socket address structure size */ #endif union { struct sockaddr sa; char data[MAXSOCKADDR]; } un; socklen_t len; len = MAXSOCKADDR; if (getsockname(sock, &un.sa, &len) < 0) { _comm_set_serrno(); XLOG_ERROR("Error getsockname() for socket %d: %s", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (un.sa.sa_family); #endif /* ! HOST_OS_WINDOWS */ }
int comm_set_bindtodevice(xsock_t sock, const char * my_ifname) { #ifdef SO_BINDTODEVICE char tmp_ifname[IFNAMSIZ]; /* * Bind a socket to an interface by name. * * Under Linux, use of the undirected broadcast address * 255.255.255.255 requires that the socket is bound to the * underlying interface, as it is an implicitly scoped address * with no meaning on its own. This is not architecturally OK, * and requires additional support for SO_BINDTODEVICE. * See socket(7) man page in Linux. * * Note: strlcpy() is not present in glibc; strncpy() is used * instead to avoid introducing a circular dependency on the * C++ library libxorp. */ strncpy(tmp_ifname, my_ifname, IFNAMSIZ-1); tmp_ifname[IFNAMSIZ-1] = '\0'; if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, tmp_ifname, sizeof(tmp_ifname)) < 0) { _comm_set_serrno(); static bool do_once = true; // Ignore EPERM..just means user isn't running as root, ie for 'scons check' // most likely..User will have bigger trouble if not running as root for // a production system anyway. if (errno != EPERM) { if (do_once) { XLOG_WARNING("setsockopt SO_BINDTODEVICE %s: %s This error will only be printed once per program instance.", tmp_ifname, comm_get_error_str(comm_get_last_error())); do_once = false; } } return (XORP_ERROR); } return (XORP_OK); #else #ifndef __FreeBSD__ // FreeBSD doesn't implement this, so no use filling logs with errors that can't // be helped. Assume calling code deals with the error code as needed. XLOG_ERROR("setsockopt SO_BINDTODEVICE %s: %s", my_ifname, "SO_BINDTODEVICE support not present."); #endif UNUSED(my_ifname); UNUSED(sock); return (XORP_ERROR); #endif }
int comm_set_send_broadcast(xsock_t sock, int val) { if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, XORP_SOCKOPT_CAST(&val), sizeof(val)) < 0) { _comm_set_serrno(); XLOG_ERROR("Error %s SO_BROADCAST on socket %d: %s", (val)? "set": "reset", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); }
int comm_set_nodelay(xsock_t sock, int val) { if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, XORP_SOCKOPT_CAST(&val), sizeof(val)) < 0) { _comm_set_serrno(); XLOG_ERROR("Error %s TCP_NODELAY on socket %d: %s", (val)? "set": "reset", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); }
int comm_sock_bind6(xsock_t sock, const struct in6_addr *my_addr, unsigned int my_ifindex, unsigned short my_port) { #ifdef HAVE_IPV6 int family; struct sockaddr_in6 sin6_addr; family = comm_sock_get_family(sock); if (family != AF_INET6) { XLOG_ERROR("Invalid family of socket %d: family = %d (expected %d)", sock, family, AF_INET6); return (XORP_ERROR); } memset(&sin6_addr, 0, sizeof(sin6_addr)); #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6_addr.sin6_len = sizeof(sin6_addr); #endif sin6_addr.sin6_family = (u_char)family; sin6_addr.sin6_port = my_port; /* XXX: in network order */ sin6_addr.sin6_flowinfo = 0; /* XXX: unused (?) */ if (my_addr != NULL) memcpy(&sin6_addr.sin6_addr, my_addr, sizeof(sin6_addr.sin6_addr)); else memcpy(&sin6_addr.sin6_addr, &in6addr_any, sizeof(sin6_addr.sin6_addr)); if (IN6_IS_ADDR_LINKLOCAL(&sin6_addr.sin6_addr)) sin6_addr.sin6_scope_id = my_ifindex; else sin6_addr.sin6_scope_id = 0; if (bind(sock, (struct sockaddr *)&sin6_addr, sizeof(sin6_addr)) < 0) { _comm_set_serrno(); XLOG_ERROR("Error binding socket (family = %d, " "my_addr = %s, my_port = %d): %s", family, (my_addr)? inet_ntop(family, my_addr, addr_str_255, sizeof(addr_str_255)) : "ANY", ntohs(my_port), comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else /* ! HAVE_IPV6 */ comm_sock_no_ipv6("comm_sock_bind6", sock, my_addr, my_ifindex, my_port); return (XORP_ERROR); #endif /* ! HAVE_IPV6 */ }
int comm_sock_listen(xsock_t sock, int backlog) { int ret; ret = listen(sock, backlog); if (ret < 0) { _comm_set_serrno(); XLOG_ERROR("Error listening on socket (socket = %d) : %s", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); }
xsock_t comm_sock_open(int domain, int type, int protocol, int is_blocking) { xsock_t sock; /* Create the kernel socket */ sock = socket(domain, type, protocol); if (sock == XORP_BAD_SOCKET) { _comm_set_serrno(); XLOG_ERROR("Error opening socket (domain = %d, type = %d, " "protocol = %d): %s", domain, type, protocol, comm_get_error_str(comm_get_last_error())); return (XORP_BAD_SOCKET); } /* Set the receiving and sending socket buffer size in the kernel */ if (comm_sock_set_rcvbuf(sock, SO_RCV_BUF_SIZE_MAX, SO_RCV_BUF_SIZE_MIN) < SO_RCV_BUF_SIZE_MIN) { _comm_set_serrno(); comm_sock_close(sock); return (XORP_BAD_SOCKET); } if (comm_sock_set_sndbuf(sock, SO_SND_BUF_SIZE_MAX, SO_SND_BUF_SIZE_MIN) < SO_SND_BUF_SIZE_MIN) { _comm_set_serrno(); comm_sock_close(sock); return (XORP_BAD_SOCKET); } /* Enable TCP_NODELAY */ if (type == SOCK_STREAM && (domain == AF_INET || domain == AF_INET6) && comm_set_nodelay(sock, 1) != XORP_OK) { _comm_set_serrno(); comm_sock_close(sock); return (XORP_BAD_SOCKET); } /* Set blocking mode */ if (comm_sock_set_blocking(sock, is_blocking) != XORP_OK) { _comm_set_serrno(); comm_sock_close(sock); return (XORP_BAD_SOCKET); } return (sock); }
int comm_sock_get_type(xsock_t sock) { int err, type; socklen_t len = sizeof(type); err = getsockopt(sock, SOL_SOCKET, SO_TYPE, XORP_SOCKOPT_CAST(&type), &len); if (err != 0) { _comm_set_serrno(); XLOG_ERROR("Error getsockopt(SO_TYPE) for socket %d: %s", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return type; }
int comm_sock_leave4(xsock_t sock, const struct in_addr *mcast_addr, const struct in_addr *my_addr) { int family; struct ip_mreq imr; /* the multicast leave address */ family = comm_sock_get_family(sock); if (family != AF_INET) { XLOG_ERROR("Invalid family of socket %d: family = %d (expected %d)", sock, family, AF_INET); return (XORP_ERROR); } memset(&imr, 0, sizeof(imr)); imr.imr_multiaddr.s_addr = mcast_addr->s_addr; if (my_addr != NULL) imr.imr_interface.s_addr = my_addr->s_addr; else imr.imr_interface.s_addr = INADDR_ANY; if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, XORP_SOCKOPT_CAST(&imr), sizeof(imr)) < 0) { char mcast_addr_str[32], my_addr_str[32]; _comm_set_serrno(); strncpy(mcast_addr_str, inet_ntoa(*mcast_addr), sizeof(mcast_addr_str) - 1); mcast_addr_str[sizeof(mcast_addr_str) - 1] = '\0'; if (my_addr != NULL) strncpy(my_addr_str, inet_ntoa(*my_addr), sizeof(my_addr_str) - 1); else strncpy(my_addr_str, "ANY", sizeof(my_addr_str) - 1); my_addr_str[sizeof(my_addr_str) - 1] = '\0'; XLOG_ERROR("Error leaving mcast group (family = %d, " "mcast_addr = %s my_addr = %s): %s", family, mcast_addr_str, my_addr_str, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); }
int comm_set_tos(xsock_t sock, int val) { #ifdef IP_TOS /* * Most implementations use 'int' to represent the value of * the IP_TOS option. */ int family, ip_tos; family = comm_sock_get_family(sock); if (family != AF_INET) { XLOG_FATAL("Error %s setsockopt IP_TOS on socket %d: " "invalid family = %d", (val)? "set": "reset", sock, family); return (XORP_ERROR); } /* * Note that it is not guaranteed that the TOS will be successfully * set or indeed propagated where the host platform is running * its own traffic classifier; the use of comm_set_tos() is * intended for link-scoped traffic. */ ip_tos = val; if (setsockopt(sock, IPPROTO_IP, IP_TOS, XORP_SOCKOPT_CAST(&ip_tos), sizeof(ip_tos)) < 0) { _comm_set_serrno(); XLOG_ERROR("setsockopt IP_TOS 0x%x: %s", ip_tos, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else UNUSED(sock); UNUSED(val); XLOG_WARNING("IP_TOS Undefined!"); return (XORP_ERROR); #endif /* ! IP_TOS */ }
int comm_sock_close(xsock_t sock) { int ret; #ifndef HOST_OS_WINDOWS ret = close(sock); #else (void)WSAEventSelect(sock, NULL, 0); ret = closesocket(sock); #endif if (ret < 0) { _comm_set_serrno(); XLOG_ERROR("Error closing socket (socket = %d) : %s", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); }
int comm_set_nosigpipe(xsock_t sock, int val) { #ifdef SO_NOSIGPIPE if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, XORP_SOCKOPT_CAST(&val), sizeof(val)) < 0) { _comm_set_serrno(); XLOG_ERROR("Error %s SO_NOSIGPIPE on socket %d: %s", (val)? "set": "reset", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else /* ! SO_NOSIGPIPE */ UNUSED(sock); UNUSED(val); XLOG_WARNING("SO_NOSIGPIPE Undefined!"); return (XORP_ERROR); #endif /* ! SO_NOSIGPIPE */ }
int comm_sock_bind4(xsock_t sock, const struct in_addr *my_addr, unsigned short my_port) { int family; struct sockaddr_in sin_addr; family = comm_sock_get_family(sock); if (family != AF_INET) { XLOG_ERROR("Invalid family of socket %d: family = %d (expected %d)", sock, family, AF_INET); return (XORP_ERROR); } memset(&sin_addr, 0, sizeof(sin_addr)); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_addr.sin_len = sizeof(sin_addr); #endif sin_addr.sin_family = (u_char)family; sin_addr.sin_port = my_port; /* XXX: in network order */ if (my_addr != NULL) sin_addr.sin_addr.s_addr = my_addr->s_addr; /* XXX: in network order */ else sin_addr.sin_addr.s_addr = INADDR_ANY; if (bind(sock, (struct sockaddr *)&sin_addr, sizeof(sin_addr)) < 0) { _comm_set_serrno(); XLOG_ERROR("Error binding socket (family = %d, " "my_addr = %s, my_port = %d): %s", family, (my_addr)? inet_ntoa(*my_addr) : "ANY", ntohs(my_port), comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); }
int comm_set_nopush(xsock_t sock, int val) { #ifdef TCP_NOPUSH /* XXX: Defined in <netinet/tcp.h> across Free/Net/OpenBSD */ if (setsockopt(sock, IPPROTO_TCP, TCP_NOPUSH, XORP_SOCKOPT_CAST(&val), sizeof(val)) < 0) { _comm_set_serrno(); XLOG_ERROR("Error %s TCP_NOPUSH on socket %d: %s", (val)? "set": "reset", sock, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else /* ! TCP_NOPUSH */ UNUSED(sock); UNUSED(val); XLOG_WARNING("TCP_NOPUSH Undefined!"); return (XORP_ERROR); #endif /* ! TCP_NOPUSH */ }
int comm_sock_leave6(xsock_t sock, const struct in6_addr *mcast_addr, unsigned int my_ifindex) { #ifdef HAVE_IPV6 int family; struct ipv6_mreq imr6; /* the multicast leave address */ family = comm_sock_get_family(sock); if (family != AF_INET6) { XLOG_ERROR("Invalid family of socket %d: family = %d (expected %d)", sock, family, AF_INET6); return (XORP_ERROR); } memset(&imr6, 0, sizeof(imr6)); memcpy(&imr6.ipv6mr_multiaddr, mcast_addr, sizeof(*mcast_addr)); imr6.ipv6mr_interface = my_ifindex; if (setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, XORP_SOCKOPT_CAST(&imr6), sizeof(imr6)) < 0) { _comm_set_serrno(); XLOG_ERROR("Error leaving mcast group (family = %d, " "mcast_addr = %s my_ifindex = %d): %s", family, inet_ntop(family, mcast_addr, addr_str_255, sizeof(addr_str_255)), my_ifindex, comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else /* ! HAVE_IPV6 */ comm_sock_no_ipv6("comm_sock_leave6", sock, mcast_addr, my_ifindex); return (XORP_ERROR); #endif /* ! HAVE_IPV6 */ }
char const * comm_get_last_error_str(void) { return comm_get_error_str(comm_get_last_error()); }
int comm_sock_connect4(xsock_t sock, const struct in_addr *remote_addr, unsigned short remote_port, int is_blocking, int *in_progress) { int family; struct sockaddr_in sin_addr; if (in_progress != NULL) *in_progress = 0; family = comm_sock_get_family(sock); if (family != AF_INET) { XLOG_ERROR("Invalid family of socket %d: family = %d (expected %d)", sock, family, AF_INET); return (XORP_ERROR); } memset(&sin_addr, 0, sizeof(sin_addr)); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_addr.sin_len = sizeof(sin_addr); #endif sin_addr.sin_family = (u_char)family; sin_addr.sin_port = remote_port; /* XXX: in network order */ sin_addr.sin_addr.s_addr = remote_addr->s_addr; /* XXX: in network order */ if (connect(sock, (struct sockaddr *)&sin_addr, sizeof(sin_addr)) < 0) { _comm_set_serrno(); if (! is_blocking) { #ifdef HOST_OS_WINDOWS if (comm_get_last_error() == WSAEWOULDBLOCK) { #else if (comm_get_last_error() == EINPROGRESS) { #endif /* * XXX: The connection is non-blocking, and the connection * cannot be completed immediately, therefore set the * in_progress flag to 1 and return an error. */ if (in_progress != NULL) *in_progress = 1; return (XORP_ERROR); } } XLOG_ERROR("Error connecting socket (family = %d, " "remote_addr = %s, remote_port = %d): %s", family, inet_ntoa(*remote_addr), ntohs(remote_port), comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); } int comm_sock_connect6(xsock_t sock, const struct in6_addr *remote_addr, unsigned short remote_port, int is_blocking, int *in_progress) { #ifdef HAVE_IPV6 int family; struct sockaddr_in6 sin6_addr; if (in_progress != NULL) *in_progress = 0; family = comm_sock_get_family(sock); if (family != AF_INET6) { XLOG_ERROR("Invalid family of socket %d: family = %d (expected %d)", sock, family, AF_INET6); return (XORP_ERROR); } memset(&sin6_addr, 0, sizeof(sin6_addr)); #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6_addr.sin6_len = sizeof(sin6_addr); #endif sin6_addr.sin6_family = (u_char)family; sin6_addr.sin6_port = remote_port; /* XXX: in network order */ sin6_addr.sin6_flowinfo = 0; /* XXX: unused (?) */ memcpy(&sin6_addr.sin6_addr, remote_addr, sizeof(sin6_addr.sin6_addr)); sin6_addr.sin6_scope_id = 0; /* XXX: unused (?) */ if (connect(sock, (struct sockaddr *)&sin6_addr, sizeof(sin6_addr)) < 0) { _comm_set_serrno(); if (! is_blocking) { #ifdef HOST_OS_WINDOWS if (comm_get_last_error() == WSAEWOULDBLOCK) { #else if (comm_get_last_error() == EINPROGRESS) { #endif /* * XXX: The connection is non-blocking, and the connection * cannot be completed immediately, therefore set the * in_progress flag to 1 and return an error. */ if (in_progress != NULL) *in_progress = 1; return (XORP_ERROR); } } XLOG_ERROR("Error connecting socket (family = %d, " "remote_addr = %s, remote_port = %d): %s", family, (remote_addr)? inet_ntop(family, remote_addr, addr_str_255, sizeof(addr_str_255)) : "ANY", ntohs(remote_port), comm_get_error_str(comm_get_last_error())); return (XORP_ERROR); } return (XORP_OK); #else /* ! HAVE_IPV6 */ if (in_progress != NULL) *in_progress = 0; comm_sock_no_ipv6("comm_sock_connect6", sock, remote_addr, remote_port, is_blocking); return (XORP_ERROR); #endif /* ! HAVE_IPV6 */ } int comm_sock_connect(xsock_t sock, const struct sockaddr *sin, int is_blocking, int *in_progress) { switch (sin->sa_family) { case AF_INET: { const struct sockaddr_in *sin4 = (const struct sockaddr_in *)((const void *)sin); return comm_sock_connect4(sock, &sin4->sin_addr, sin4->sin_port, is_blocking, in_progress); } break; #ifdef HAVE_IPV6 case AF_INET6: { const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)((const void *)sin); return comm_sock_connect6(sock, &sin6->sin6_addr, sin6->sin6_port, is_blocking, in_progress); } break; #endif /* HAVE_IPV6 */ default: XLOG_FATAL("Error comm_sock_connect invalid family = %d", sin->sa_family); return (XORP_ERROR); } XLOG_UNREACHABLE(); return XORP_ERROR; } xsock_t comm_sock_accept(xsock_t sock) { xsock_t sock_accept; struct sockaddr addr; socklen_t socklen = sizeof(addr); sock_accept = accept(sock, &addr, &socklen); if (sock_accept == XORP_BAD_SOCKET) { _comm_set_serrno(); XLOG_ERROR("Error accepting socket %d: %s", sock, comm_get_error_str(comm_get_last_error())); return (XORP_BAD_SOCKET); } #ifdef HOST_OS_WINDOWS /* * Squelch Winsock event notifications on the new socket which may * have been inherited from the parent listening socket. */ (void)WSAEventSelect(sock_accept, NULL, 0); #endif /* Enable TCP_NODELAY */ if ((addr.sa_family == AF_INET || addr.sa_family == AF_INET6) && comm_set_nodelay(sock_accept, 1) != XORP_OK) { comm_sock_close(sock_accept); return (XORP_BAD_SOCKET); } return (sock_accept); }