summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/socket_wrapper/socket_wrapper.c121
1 files changed, 35 insertions, 86 deletions
diff --git a/lib/socket_wrapper/socket_wrapper.c b/lib/socket_wrapper/socket_wrapper.c
index e3dd4507f8..2f9dc1b0ef 100644
--- a/lib/socket_wrapper/socket_wrapper.c
+++ b/lib/socket_wrapper/socket_wrapper.c
@@ -2132,8 +2132,11 @@ _PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct
_PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
{
+ struct msghdr msg;
+ struct iovec tmp;
struct sockaddr_un un_addr;
- int ret;
+ const struct sockaddr_un *to_un = NULL;
+ ssize_t ret;
struct socket_info *si = find_socket_info(s);
int bcast = 0;
@@ -2141,104 +2144,50 @@ _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, con
return real_sendto(s, buf, len, flags, to, tolen);
}
- if (si->connected) {
- if (to) {
- errno = EISCONN;
- return -1;
- }
+ tmp.iov_base = discard_const_p(char, buf);
+ tmp.iov_len = len;
- to = si->peername;
- tolen = si->peername_len;
- }
+ msg.msg_name = discard_const_p(struct sockaddr, to); /* optional address */
+ msg.msg_namelen = tolen; /* size of address */
+ msg.msg_iov = &tmp; /* scatter/gather array */
+ msg.msg_iovlen = 1; /* # elements in msg_iov */
+ msg.msg_control = NULL; /* ancillary data, see below */
+ msg.msg_controllen = 0; /* ancillary data buffer len */
+ msg.msg_flags = 0; /* flags on received message */
- switch (si->type) {
- case SOCK_STREAM:
- /* cut down to 1500 byte packets for stream sockets,
- * which makes it easier to format PCAP capture files
- * (as the caller will simply continue from here) */
- len = MIN(len, 1500);
-
- ret = real_send(s, buf, len, flags);
- break;
- case SOCK_DGRAM:
- if (si->bound == 0) {
- ret = swrap_auto_bind(si, si->family);
- if (ret == -1) return -1;
- }
-
- ret = sockaddr_convert_to_un(si, to, tolen, &un_addr, 0, &bcast);
- if (ret == -1) return -1;
-
- if (bcast) {
- struct stat st;
- unsigned int iface;
- unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
- char type;
+ ret = swrap_sendmsg_before(si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
+ if (ret == -1) return -1;
- type = SOCKET_TYPE_CHAR_UDP;
+ buf = msg.msg_iov[0].iov_base;
+ len = msg.msg_iov[0].iov_len;
- for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
- snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
- socket_wrapper_dir(), type, iface, prt);
- if (stat(un_addr.sun_path, &st) != 0) continue;
+ if (bcast) {
+ struct stat st;
+ unsigned int iface;
+ unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
+ char type;
- /* ignore the any errors in broadcast sends */
- real_sendto(s, buf, len, flags,
- (struct sockaddr *)(void *)&un_addr,
- sizeof(un_addr));
- }
+ type = SOCKET_TYPE_CHAR_UDP;
- swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+ for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
+ snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
+ socket_wrapper_dir(), type, iface, prt);
+ if (stat(un_addr.sun_path, &st) != 0) continue;
- return len;
+ /* ignore the any errors in broadcast sends */
+ real_sendto(s, buf, len, flags,
+ (struct sockaddr *)(void *)&un_addr,
+ sizeof(un_addr));
}
- if (si->defer_connect) {
- ret = real_connect(s, (struct sockaddr *)(void *)&un_addr,
- sizeof(un_addr));
-
- /* to give better errors */
- if (ret == -1 && errno == ENOENT) {
- errno = EHOSTUNREACH;
- }
-
- if (ret == -1) {
- return ret;
- }
- si->defer_connect = 0;
- }
+ swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
- /* Man page for Linux says:
- * "the error EISONN may be returned when they are not NULL and 0"
- * But in practice it's not on x86/amd64, but on other unix it is
- * (ie. freebsd)
- * So if we are already connected we send NULL/0
- */
- if (si->connected) {
- ret = real_sendto(s, buf, len, flags, NULL, 0);
- } else {
- ret = real_sendto(s, buf, len, flags,
- (struct sockaddr *)(void *)&un_addr,
- sizeof(un_addr));
- }
- break;
- default:
- ret = -1;
- errno = EHOSTUNREACH;
- break;
+ return len;
}
- /* to give better errors */
- if (ret == -1 && errno == ENOENT) {
- errno = EHOSTUNREACH;
- }
+ ret = real_sendto(s, buf, len, flags, msg.msg_name, msg.msg_namelen);
- if (ret == -1) {
- swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
- swrap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
- } else {
- swrap_dump_packet(si, to, SWRAP_SENDTO, buf, ret);
- }
+ swrap_sendmsg_after(si, &msg, to, ret);
return ret;
}