[sheepdog] [PATCH] sheep: bind TCP ports as soon as possible
Hitoshi Mitake
mitake.hitoshi at gmail.com
Sun Mar 31 18:23:58 CEST 2013
Current binding of TCP ports is done after some parts of
initialization e.g. log_init(). Because of this behaviour, confusing
logs can be created. These logs would contain interleaving messages
from different sheep processes (e.g. sudden "failed to bind server
socket: Address already in use").
This patch forbids such a problem by making a part of binding TCP
sockets independent. This patch splits create_listen_port() into two
functions: create_listen_fds() and create_listen_events(). main() of
sheep calls create_listen_fds(), the function for creating bind()ed
fds, direct after calling early_log_init(). The latter
create_listen_events(), the function for registering events based on
fds created by create_listen_fds(), is called after init_event().
Signed-off-by: Hitoshi Mitake <mitake.hitoshi at lab.ntt.co.jp>
---
include/net.h | 4 ++--
lib/net.c | 22 ++++++++++++----------
sheep/request.c | 29 ++++++++++++++++++++++++++---
sheep/sheep.c | 31 ++++++++++++++++++++++++++++---
sheep/sheep_priv.h | 1 +
5 files changed, 69 insertions(+), 18 deletions(-)
diff --git a/include/net.h b/include/net.h
index a68c880..3f8663f 100644
--- a/include/net.h
+++ b/include/net.h
@@ -57,8 +57,8 @@ int send_req(int sockfd, struct sd_req *hdr, void *data, unsigned int wlen,
bool (*need_retry)(uint32_t), uint32_t);
int exec_req(int sockfd, struct sd_req *hdr, void *,
bool (*need_retry)(uint32_t), uint32_t);
-int create_listen_ports(const char *bindaddr, int port,
- int (*callback)(int fd, void *), void *data);
+int create_listen_fds(const char *bindaddr, int port,
+ int **fds, int *nr_fds_res);
int create_unix_domain_socket(const char *unix_path,
int (*callback)(int, void *), void *data);
diff --git a/lib/net.c b/lib/net.c
index ff0c150..0f2c36f 100644
--- a/lib/net.c
+++ b/lib/net.c
@@ -113,13 +113,14 @@ notrace int tx(struct connection *conn, enum conn_state next_state)
return ret;
}
-int create_listen_ports(const char *bindaddr, int port,
- int (*callback)(int fd, void *), void *data)
+int create_listen_fds(const char *bindaddr, int port,
+ int **fds_res, int *nr_fds_res)
{
char servname[64];
- int fd, ret, opt;
+ int fd, ret, opt, nr_fds;
int success = 0;
struct addrinfo hints, *res, *res0;
+ int *fds;
memset(servname, 0, sizeof(servname));
snprintf(servname, sizeof(servname), "%d", port);
@@ -134,6 +135,11 @@ int create_listen_ports(const char *bindaddr, int port,
return 1;
}
+ nr_fds = 0;
+ for (res = res0; res; res = res->ai_next)
+ nr_fds++;
+ fds = xcalloc(nr_fds, sizeof(int));
+
for (res = res0; res; res = res->ai_next) {
fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (fd < 0)
@@ -175,13 +181,7 @@ int create_listen_ports(const char *bindaddr, int port,
continue;
}
- ret = callback(fd, data);
- if (ret) {
- close(fd);
- continue;
- }
-
- success++;
+ fds[success++] = fd;
}
freeaddrinfo(res0);
@@ -189,6 +189,8 @@ int create_listen_ports(const char *bindaddr, int port,
if (!success)
sd_eprintf("failed to create a listening port");
+ *fds_res = fds;
+ *nr_fds_res = success;
return !success;
}
diff --git a/sheep/request.c b/sheep/request.c
index bd0f170..3a05604 100644
--- a/sheep/request.c
+++ b/sheep/request.c
@@ -877,10 +877,33 @@ static int create_listen_port_fn(int fd, void *data)
int create_listen_port(char *bindaddr, int port)
{
- static bool is_inet_socket = true;
+ int *fds, nr_fds;
+ int ret;
+
+ ret = create_listen_fds(bindaddr, port, &fds, &nr_fds);
+ if (ret)
+ exit(1);
+
+ ret = create_listen_events(fds, nr_fds);
+ if (ret)
+ exit(1);
+ free(fds);
+
+ return ret;
+}
- return create_listen_ports(bindaddr, port, create_listen_port_fn,
- &is_inet_socket);
+int create_listen_events(int *fds, int nr_fds)
+{
+ int i, ret;
+ static bool is_inet = true;
+
+ for (i = 0; i < nr_fds; i++) {
+ ret = register_event(fds[i], listen_handler, &is_inet);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
int init_unix_domain_socket(const char *dir)
diff --git a/sheep/sheep.c b/sheep/sheep.c
index 4fa7d58..1445061 100644
--- a/sheep/sheep.c
+++ b/sheep/sheep.c
@@ -402,6 +402,9 @@ int main(int argc, char **argv)
const char *log_format = "default";
static struct logger_user_info sheep_info;
+ int *bind_fds, nr_bind_fds;
+ int *io_bind_fds, nr_io_bind_fds;
+
install_crash_handler(crash_handler);
signal(SIGPIPE, SIG_IGN);
@@ -556,6 +559,23 @@ int main(int argc, char **argv)
sheep_info.port = port;
early_log_init(log_format, &sheep_info);
+ /*
+ * These create_listen_fds() must be called before writing anything on
+ * log files.
+ * Because there is a possibility that another sheep process is already
+ * using the port. If the conflict rises, it should be reported ASAP.
+ */
+ ret = create_listen_fds(bindaddr, port, &bind_fds, &nr_bind_fds);
+ if (ret)
+ exit(1);
+
+ if (io_addr) {
+ ret = create_listen_fds(io_addr, io_port, &io_bind_fds,
+ &nr_io_bind_fds);
+ if (ret)
+ exit(1);
+ }
+
if (nr_vnodes == 0) {
sys->gateway_only = true;
sys->disk_space = 0;
@@ -597,12 +617,17 @@ int main(int argc, char **argv)
if (ret)
exit(1);
- ret = create_listen_port(bindaddr, port);
+ ret = create_listen_events(bind_fds, nr_bind_fds);
if (ret)
exit(1);
+ free(bind_fds);
- if (io_addr && create_listen_port(io_addr, io_port))
- exit(1);
+ if (io_addr) {
+ ret = create_listen_events(io_bind_fds, nr_io_bind_fds);
+ if (ret)
+ exit(1);
+ free(io_bind_fds);
+ }
ret = init_unix_domain_socket(dir);
if (ret)
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index 652fd3a..534e1e1 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -220,6 +220,7 @@ static inline uint32_t sys_epoch(void)
int create_listen_port(char *bindaddr, int port);
int init_unix_domain_socket(const char *dir);
+int create_listen_events(int *fds, int nr_fds);
int init_store_driver(bool is_gateway);
int init_global_pathnames(const char *d, char *);
--
1.7.5.1
More information about the sheepdog
mailing list