--- ./haproxy.c~ Sun Nov 14 16:13:34 2004 +++ ./haproxy.c Sat Nov 27 13:35:50 2004 @@ -339,6 +353,7 @@ #define SRV_RUNNING 1 /* the server is UP */ #define SRV_BACKUP 2 /* this server is a backup server */ #define SRV_MAPPORTS 4 /* this server uses mapped ports */ +#define SRV_BIND_SRC 8 /* this server uses a specific source address */ /* what to do when a header matches a regex */ #define ACT_ALLOW 0 /* allow the request */ @@ -403,6 +418,7 @@ char *cookie; /* the id set in the cookie */ char *id; /* just for identification */ struct sockaddr_in addr; /* the address to connect to */ + struct sockaddr_in source_addr; /* the address to which we want to bind for connect() */ short check_port; /* the port to use for the health checks */ int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */ int rise, fall; /* time in iterations */ @@ -1624,12 +1640,26 @@ return -1; } - /* allow specific binding */ - if (s->proxy->options & PR_O_BIND_SRC && - bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) { - Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id); - close(fd); - return -1; + /* allow specific binding : + * - server-specific at first + * - proxy-specific next + */ + if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) { + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)); + if (bind(fd, (struct sockaddr *)&s->srv->source_addr, sizeof(s->srv->source_addr)) == -1) { + Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n", + s->proxy->id, s->srv->id); + close(fd); + return -1; + } + } + else if (s->proxy->options & PR_O_BIND_SRC) { + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)); + if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) { + Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id); + close(fd); + return -1; + } } if ((connect(fd, (struct sockaddr *)&s->srv_addr, sizeof(s->srv_addr)) == -1) && (errno != EINPROGRESS)) { @@ -4179,32 +4209,48 @@ sa = s->addr; sa.sin_port = htons(s->check_port); - /* allow specific binding */ - if (s->proxy->options & PR_O_BIND_SRC && - bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) { - Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", s->proxy->id); - close(fd); - s->result = -1; - } - else if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) { - /* OK, connection in progress or established */ - - //fprintf(stderr, "process_chk: 4\n"); - - s->curfd = fd; /* that's how we know a test is in progress ;-) */ - fdtab[fd].owner = t; - fdtab[fd].read = &event_srv_chk_r; - fdtab[fd].write = &event_srv_chk_w; - fdtab[fd].state = FD_STCONN; /* connection in progress */ - FD_SET(fd, StaticWriteEvent); /* for connect status */ - fd_insert(fd); - /* FIXME: we allow up to for a connection to establish, but we should use another parameter */ - tv_delayfrom(&t->expire, &now, s->inter); - task_queue(t); /* restore t to its place in the task list */ - return tv_remain(&now, &t->expire); + /* allow specific binding : + * - server-specific at first + * - proxy-specific next + */ + if (s->state & SRV_BIND_SRC) { + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)); + if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) { + Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n", + s->proxy->id, s->id); + s->result = -1; + } } - else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) { - s->result = -1; /* a real error */ + else if (s->proxy->options & PR_O_BIND_SRC) { + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)); + if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) { + Alert("Cannot bind to source address before connect() for proxy %s. Aborting.\n", + s->proxy->id); + s->result = -1; + } + } + + if (!s->result) { + if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) { + /* OK, connection in progress or established */ + + //fprintf(stderr, "process_chk: 4\n"); + + s->curfd = fd; /* that's how we know a test is in progress ;-) */ + fdtab[fd].owner = t; + fdtab[fd].read = &event_srv_chk_r; + fdtab[fd].write = &event_srv_chk_w; + fdtab[fd].state = FD_STCONN; /* connection in progress */ + FD_SET(fd, StaticWriteEvent); /* for connect status */ + fd_insert(fd); + /* FIXME: we allow up to for a connection to establish, but we should use another parameter */ + tv_delayfrom(&t->expire, &now, s->inter); + task_queue(t); /* restore t to its place in the task list */ + return tv_remain(&now, &t->expire); + } + else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) { + s->result = -1; /* a real error */ + } } } //fprintf(stderr, "process_chk: 5\n"); @@ -5335,8 +5381,18 @@ do_check = 1; cur_arg += 1; } + else if (!strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */ + if (!*args[cur_arg + 1]) { + Alert("parsing [%s:%d] : '%s' expects [:] as argument.\n", + file, linenum, "source"); + return -1; + } + newsrv->state |= SRV_BIND_SRC; + newsrv->source_addr = *str2sa(args[cur_arg + 1]); + cur_arg += 2; + } else { - Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise' and 'fall'.\n", + Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'port' and 'source'.\n", file, linenum, newsrv->id); return -1; }