]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[BUG] stream_sock: use get_addr_len() instead of sizeof() on sockaddr_storage
authorWilly Tarreau <w@1wt.eu>
Tue, 5 Apr 2011 14:56:50 +0000 (16:56 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 5 Apr 2011 14:56:50 +0000 (16:56 +0200)
John Helliwell reported a runtime issue on Solaris since 1.5-dev5. Traces
show that connect() returns EINVAL, which means the socket length is not
appropriate for the family. Solaris does not like being called with sizeof
and needs the address family's size on sockaddr_storage.

The fix consists in adding a get_addr_len() function which returns the
socket's address length based on its family. Tests show that this works
for both IPv4 and IPv6 addresses.

include/common/standard.h
src/checks.c
src/log.c
src/proto_tcp.c

index e7a1052841528b4e1005b5ea9680759fa05e9817..0082087336f9e046f72168341f546e2a2287f910 100644 (file)
@@ -525,6 +525,20 @@ static inline int get_host_port(struct sockaddr_storage *addr)
        return 0;
 }
 
+/* returns address len for <addr>'s family, 0 for unknown families */
+static inline int get_addr_len(const struct sockaddr_storage *addr)
+{
+       switch (addr->ss_family) {
+       case AF_INET:
+               return sizeof(struct sockaddr_in);
+       case AF_INET6:
+               return sizeof(struct sockaddr_in6);
+       case AF_UNIX:
+               return sizeof(struct sockaddr_un);
+       }
+       return 0;
+}
+
 /* set port in host byte order */
 static inline int set_net_port(struct sockaddr_storage *addr, int port)
 {
index 147a7abd67b5ada6aa8aa685b0d526e722ffe989..4285624cf32cfa45625dfa55b1df10ab8b9806aa 100644 (file)
@@ -817,16 +817,9 @@ static int event_srv_chk_w(int fd)
                        else
                                sa = s->addr;
 
-                       switch (s->check_addr.ss_family) {
-                       case AF_INET:
-                               ((struct sockaddr_in *)&sa)->sin_port = htons(s->check_port);
-                               break;
-                       case AF_INET6:
-                               ((struct sockaddr_in6 *)&sa)->sin6_port = htons(s->check_port);
-                               break;
-                       }
+                       set_host_port(&sa, s->check_port);
 
-                       if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == 0)
+                       if (connect(fd, (struct sockaddr *)&sa, get_addr_len(&sa)) == 0)
                                errno = 0;
 
                        if (errno == EALREADY || errno == EINPROGRESS)
@@ -1377,7 +1370,7 @@ struct task *process_chk(struct task *t)
                                        if (s->proxy->options2 & PR_O2_SMARTCON)
                                                setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (char *) &zero, sizeof(zero));
 #endif
-                                       if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
+                                       if ((connect(fd, (struct sockaddr *)&sa, get_addr_len(&sa)) != -1) || (errno == EINPROGRESS)) {
                                                /* OK, connection in progress or established */
                        
                                                //fprintf(stderr, "process_chk: 4\n");
@@ -1390,7 +1383,7 @@ struct task *process_chk(struct task *t)
                                                fdtab[fd].cb[DIR_WR].f = &event_srv_chk_w;
                                                fdtab[fd].cb[DIR_WR].b = NULL;
                                                fdinfo[fd].peeraddr = (struct sockaddr *)&sa;
-                                               fdinfo[fd].peerlen = sizeof(sa);
+                                               fdinfo[fd].peerlen = get_addr_len(&sa);
                                                fdtab[fd].state = FD_STCONN; /* connection in progress */
                                                fdtab[fd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
                                                EV_FD_SET(fd, DIR_WR);  /* for connect status */
index eba9adf0ef543303842bb20215aa930d684fd202..58d884a54aad1a9e708a7ee9e0948354c7ba2872 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -289,7 +289,8 @@ void send_log(struct proxy *p, int level, const char *message, ...)
        
                /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
                sent = sendto(*plogfd, log_ptr, dataptr + data_len - log_ptr,
-                       MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *)&logsrv->addr, sizeof(logsrv->addr));
+                             MSG_DONTWAIT | MSG_NOSIGNAL,
+                             (struct sockaddr *)&logsrv->addr, get_addr_len(&logsrv->addr));
                if (sent < 0) {
                        Alert("sendto logger #%d failed: %s (errno=%d)\n",
                                nblogger, strerror(errno), errno);
index ca993a6fc35afbeffb2d57f5f2eb24c6c4a7fe50..13ea2103cb6e0e968a5c2e2cffaa4a7358d7b466 100644 (file)
@@ -150,12 +150,12 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so
 
        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
        if (foreign_ok) {
-               ret = bind(fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
+               ret = bind(fd, (struct sockaddr *)&bind_addr, get_addr_len(&bind_addr));
                if (ret < 0)
                        return 2;
        }
        else {
-               ret = bind(fd, (struct sockaddr *)local, sizeof(*local));
+               ret = bind(fd, (struct sockaddr *)local, get_addr_len(local));
                if (ret < 0)
                        return 1;
        }
@@ -406,7 +406,7 @@ int tcp_connect_server(struct stream_interface *si)
        if (global.tune.server_rcvbuf)
                 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
 
-       if ((connect(fd, (struct sockaddr *)&si->addr.s.to, sizeof(struct sockaddr_storage)) == -1) &&
+       if ((connect(fd, (struct sockaddr *)&si->addr.s.to, get_addr_len(&si->addr.s.to)) == -1) &&
            (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
 
                if (errno == EAGAIN || errno == EADDRINUSE) {
@@ -449,7 +449,7 @@ int tcp_connect_server(struct stream_interface *si)
        fdtab[fd].cb[DIR_WR].b = si->ob;
 
        fdinfo[fd].peeraddr = (struct sockaddr *)&si->addr.s.to;
-       fdinfo[fd].peerlen = sizeof(struct sockaddr_storage);
+       fdinfo[fd].peerlen = get_addr_len(&si->addr.s.to);
 
        fd_insert(fd);
        EV_FD_SET(fd, DIR_WR);  /* for connect status */