From: Pete Zaitcev <zaitcev@redhat.com>
To: Jeff Garzik <jeff@garzik.org>
Cc: Project Hail List <hail-devel@vger.kernel.org>
Subject: [Patch 1/2] cld: implement dynamic port
Date: Wed, 2 Sep 2009 20:48:58 -0600 [thread overview]
Message-ID: <20090902204858.7a3e34a9@redhat.com> (raw)
This patch is needed to build on Fedora. The buildsystem can run two
builds on the same system in the same time (for example, one for 32-bit
buildroot, and another for 64-bit buildroot). Since we include
"make check" step, port numbers used by simultaneous builds conflict,
causing the build to fail.
Keeping a patch for this in Fedora is additional labor placed on
maintainer, and there's a remote possibility that it may be useful
for someone else, so let's include this feature.
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
diff --git a/include/cld_msg.h b/include/cld_msg.h
index e4c8f28..641b857 100644
--- a/include/cld_msg.h
+++ b/include/cld_msg.h
@@ -258,5 +258,6 @@ struct cld_msg_event {
extern unsigned long long cld_sid2llu(const uint8_t *sid);
extern void __cld_rand64(void *p);
extern const char *cld_errstr(enum cle_err_codes ecode);
+extern int cld_readport(const char *fname);
#endif /* __CLD_MSG_H__ */
diff --git a/lib/common.c b/lib/common.c
index a4eda54..68f60f8 100644
--- a/lib/common.c
+++ b/lib/common.c
@@ -1,5 +1,8 @@
#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
#include <glib.h>
#include <cld-private.h>
#include "cld_msg.h"
@@ -53,3 +56,31 @@ const char *cld_errstr(enum cle_err_codes ecode)
return cld_errlist[ecode];
}
+/*
+ * Read a port number from a port file, return the value or negative error.
+ */
+int cld_readport(const char *fname)
+{
+ enum { LEN = 11 };
+ char buf[LEN+1];
+ long port;
+ int fd;
+ int rc;
+
+ if ((fd = open(fname, O_RDONLY)) == -1)
+ return -errno;
+ rc = read(fd, buf, LEN);
+ close(fd);
+ if (rc < 0)
+ return -errno;
+ if (rc == 0)
+ return -EPIPE;
+ buf[rc] = 0;
+
+ port = strtol(buf, NULL, 10);
+ if (port <= 0 || port >= 65636)
+ return -EDOM;
+
+ return (int)port;
+}
+
diff --git a/server/cld.h b/server/cld.h
index 537f07a..e5ea9aa 100644
--- a/server/cld.h
+++ b/server/cld.h
@@ -113,6 +113,8 @@ struct server {
int pid_fd;
char *port; /* bind port */
+ char *port_file; /* Port file to write */
+ bool port_set;
struct cldb cldb; /* database info */
diff --git a/server/server.c b/server/server.c
index 9bf328b..ef8a060 100644
--- a/server/server.c
+++ b/server/server.c
@@ -32,6 +32,7 @@
#include <argp.h>
#include <netdb.h>
#include <signal.h>
+#include <netinet/in.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <cld-private.h>
@@ -66,6 +67,8 @@ static struct argp_option options[] = {
{ "strict-free", 1001, NULL, 0,
"For memory-checker runs. When shutting down server, free local "
"heap, rather than simply exit(2)ing and letting OS clean up." },
+ { "port-file", 1002, "FILE", 0,
+ "Write the listen port to FILE. Implies bind to zero." },
{ }
};
@@ -600,7 +603,117 @@ static void net_close(void)
}
}
-static int net_open(void)
+static int net_open_socket(int addr_fam, int sock_type, int sock_prot,
+ int addr_len, void *addr_ptr)
+{
+ struct server_poll sp;
+ struct pollfd pfd;
+ int fd, on;
+ int rc;
+
+ fd = socket(addr_fam, sock_type, sock_prot);
+ if (fd < 0) {
+ syslogerr("tcp socket");
+ return -errno;
+ }
+
+ on = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
+ syslogerr("setsockopt(SO_REUSEADDR)");
+ close(fd);
+ return -errno;
+ }
+
+ if (bind(fd, addr_ptr, addr_len) < 0) {
+ syslogerr("tcp bind");
+ close(fd);
+ return -errno;
+ }
+
+ rc = fsetflags("udp server", fd, O_NONBLOCK);
+ if (rc) {
+ close(fd);
+ return -errno;
+ }
+
+ sp.fd = fd;
+ sp.cb = udp_srv_event;
+ sp.userdata = NULL;
+ g_array_append_val(cld_srv.poll_data, sp);
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ g_array_append_val(cld_srv.polls, pfd);
+
+ return fd;
+}
+
+static int net_open_any(void)
+{
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ FILE *portf;
+ int fd4, fd6;
+ socklen_t addr_len;
+ unsigned short port;
+ int rc;
+
+ port = 0;
+
+ /* Thanks to Linux, IPv6 must be bound first. */
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+ memcpy(&addr6.sin6_addr, &in6addr_any, sizeof(struct in6_addr));
+ fd6 = net_open_socket(AF_INET6, SOCK_DGRAM, 0, sizeof(addr6), &addr6);
+
+ if (fd6 >= 0) {
+ addr_len = sizeof(addr6);
+ if (getsockname(fd6, &addr6, &addr_len) != 0) {
+ rc = errno;
+ cldlog(LOG_ERR, "getsockname failed: %s", strerror(rc));
+ return -rc;
+ }
+ port = ntohs(addr6.sin6_port);
+ }
+
+ memset(&addr4, 0, sizeof(addr4));
+ addr4.sin_family = AF_INET;
+ addr4.sin_addr.s_addr = htonl(INADDR_ANY);
+ /* If IPv6 worked, we must use the same port number for IPv4 */
+ if (port)
+ addr4.sin_port = port;
+ fd4 = net_open_socket(AF_INET, SOCK_DGRAM, 0, sizeof(addr4), &addr4);
+
+ if (!port) {
+ if (fd4 < 0)
+ return fd4;
+
+ addr_len = sizeof(addr4);
+ if (getsockname(fd4, &addr4, &addr_len) != 0) {
+ rc = errno;
+ cldlog(LOG_ERR, "getsockname failed: %s", strerror(rc));
+ return -rc;
+ }
+ port = ntohs(addr4.sin_port);
+ }
+
+ cldlog(LOG_INFO, "Listening on port %u", port);
+
+ portf = fopen(cld_srv.port_file, "w");
+ if (portf == NULL) {
+ rc = errno;
+ cldlog(LOG_INFO, "Cannot create port file %s: %s",
+ cld_srv.port_file, strerror(rc));
+ return -rc;
+ }
+ fprintf(portf, "%u\n", port);
+ fclose(portf);
+
+ return 0;
+}
+
+static int net_open_known(const char *portstr)
{
int ipv6_found = 0;
int rc;
@@ -611,10 +724,10 @@ static int net_open(void)
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
- rc = getaddrinfo(NULL, cld_srv.port, &hints, &res0);
+ rc = getaddrinfo(NULL, portstr, &hints, &res0);
if (rc) {
cldlog(LOG_ERR, "getaddrinfo(*:%s) failed: %s",
- cld_srv.port, gai_strerror(rc));
+ portstr, gai_strerror(rc));
rc = -EINVAL;
goto err_addr;
}
@@ -637,50 +750,16 @@ static int net_open(void)
#endif
for (res = res0; res; res = res->ai_next) {
- struct server_poll sp;
- struct pollfd pfd;
- int fd, on;
char listen_host[65], listen_serv[65];
if (ipv6_found && res->ai_family == PF_INET)
continue;
- fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
- if (fd < 0) {
- syslogerr("tcp socket");
- return -errno;
- }
-
- on = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on,
- sizeof(on)) < 0) {
- syslogerr("setsockopt(SO_REUSEADDR)");
- rc = -errno;
+ rc = net_open_socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol,
+ res->ai_addrlen, res->ai_addr);
+ if (rc < 0)
goto err_out;
- }
-
- if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {
- syslogerr("tcp bind");
- close(fd);
- rc = -errno;
- goto err_out;
- }
-
- rc = fsetflags("udp server", fd, O_NONBLOCK);
- if (rc) {
- close(fd);
- goto err_out;
- }
-
- sp.fd = fd;
- sp.cb = udp_srv_event;
- sp.userdata = NULL;
- g_array_append_val(cld_srv.poll_data, sp);
-
- pfd.fd = fd;
- pfd.events = POLLIN;
- pfd.revents = 0;
- g_array_append_val(cld_srv.polls, pfd);
getnameinfo(res->ai_addr, res->ai_addrlen,
listen_host, sizeof(listen_host),
@@ -701,6 +780,14 @@ err_addr:
return rc;
}
+static int net_open(void)
+{
+ if (cld_srv.port_file)
+ return net_open_any();
+ else
+ return net_open_known(cld_srv.port);
+}
+
static void segv_signal(int signo)
{
cldlog(LOG_ERR, "SIGSEGV");
@@ -749,9 +836,10 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
cld_srv.flags |= SFL_FOREGROUND;
break;
case 'p':
- if (atoi(arg) > 0 && atoi(arg) < 65536)
+ if (atoi(arg) > 0 && atoi(arg) < 65536) {
cld_srv.port = arg;
- else {
+ cld_srv.port_set = true;
+ } else {
fprintf(stderr, "invalid port: '%s'\n", arg);
argp_usage(state);
}
@@ -763,6 +851,9 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
case 1001: /* --strict-free */
strict_free = true;
break;
+ case 1002:
+ cld_srv.port_file = arg;
+ break;
case ARGP_KEY_ARG:
argp_usage(state); /* too many args */
@@ -797,6 +888,11 @@ int main (int argc, char *argv[])
fprintf(stderr, "argp_parse failed: %s\n", strerror(aprc));
return 1;
}
+ if (cld_srv.port_set && cld_srv.port_file) {
+ fprintf(stderr, "Options --port and --port-file must not"
+ " be set together\n");
+ return 1;
+ }
/*
* open syslog, background outselves, write PID file ASAP
diff --git a/test/it-works.c b/test/it-works.c
index 9bec2a7..bd2f965 100644
--- a/test/it-works.c
+++ b/test/it-works.c
@@ -72,9 +72,16 @@ static struct cldc_ops ops = {
static int init(void)
{
int rc;
+ int port;
struct cldc_call_opts copts;
- rc = cldc_udp_new("localhost", 18181, &udp);
+ port = cld_readport("cld.port"); /* FIXME need test.h */
+ if (port < 0)
+ return port;
+ if (port == 0)
+ return -1;
+
+ rc = cldc_udp_new("localhost", port, &udp);
if (rc)
return rc;
diff --git a/test/load-file-event.c b/test/load-file-event.c
index 3274787..1620508 100644
--- a/test/load-file-event.c
+++ b/test/load-file-event.c
@@ -188,6 +188,7 @@ static struct cldc_ops ops = {
static int init(char *name)
{
int rc;
+ int port;
struct cldc_call_opts copts;
run.fname = name;
@@ -202,7 +203,13 @@ static int init(char *name)
run.len = rc;
#endif
- rc = cldc_udp_new("localhost", 18181, &run.udp);
+ port = cld_readport("cld.port"); /* FIXME need test.h */
+ if (port < 0)
+ return port;
+ if (port == 0)
+ return -1;
+
+ rc = cldc_udp_new("localhost", port, &run.udp);
if (rc)
return rc;
diff --git a/test/lock-file-event.c b/test/lock-file-event.c
index cbf1647..c69da66 100644
--- a/test/lock-file-event.c
+++ b/test/lock-file-event.c
@@ -208,11 +208,18 @@ static struct cldc_ops ops = {
static int init(void)
{
int rc;
+ int port;
struct cldc_call_opts copts;
memcpy(run.buf, TESTSTR, TESTLEN);
- rc = cldc_udp_new("localhost", 18181, &run.udp);
+ port = cld_readport("cld.port"); /* FIXME need test.h */
+ if (port < 0)
+ return port;
+ if (port == 0)
+ return -1;
+
+ rc = cldc_udp_new("localhost", port, &run.udp);
if (rc)
return rc;
diff --git a/test/pid-exists b/test/pid-exists
index 351b4f1..34c7258 100755
--- a/test/pid-exists
+++ b/test/pid-exists
@@ -2,7 +2,13 @@
if [ ! -f cld.pid ]
then
- echo "pid file not found."
+ echo "pid file not found." >&2
+ exit 1
+fi
+
+if [ ! -f cld.port ]
+then
+ echo "port file not found." >&2
exit 1
fi
diff --git a/test/save-file-event.c b/test/save-file-event.c
index 01a0331..1b3418a 100644
--- a/test/save-file-event.c
+++ b/test/save-file-event.c
@@ -191,6 +191,7 @@ static struct cldc_ops ops = {
static int init(char *name)
{
int rc;
+ int port;
struct cldc_call_opts copts;
run.fname = name;
@@ -208,7 +209,13 @@ static int init(char *name)
run.len = TESTLEN;
#endif
- rc = cldc_udp_new("localhost", 18181, &run.udp);
+ port = cld_readport("cld.port"); /* FIXME need test.h */
+ if (port < 0)
+ return port;
+ if (port == 0)
+ return -1;
+
+ rc = cldc_udp_new("localhost", port, &run.udp);
if (rc)
return rc;
diff --git a/test/start-daemon b/test/start-daemon
index 4cb9fd7..25cdab4 100755
--- a/test/start-daemon
+++ b/test/start-daemon
@@ -6,7 +6,12 @@ then
exit 1
fi
-../server/cld -P cld.pid -d "$PWD/data" -p 18181 -E
+## Static port
+cldport=18181
+echo $cldport > cld.port
+../server/cld -P cld.pid -d "$PWD/data" -p $cldport -E
+## Dynamic port
+# ../server/cld -P cld.pid -d "$PWD/data" --port-file=cld.port -E
sleep 3
diff --git a/test/stop-daemon b/test/stop-daemon
index 27d985e..1949dc4 100755
--- a/test/stop-daemon
+++ b/test/stop-daemon
@@ -1,5 +1,7 @@
#!/bin/sh
+rm -f cld.port
+
if [ ! -f cld.pid ]
then
echo no daemon pid file found.
next reply other threads:[~2009-09-03 2:48 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-03 2:48 Pete Zaitcev [this message]
2009-09-09 19:01 ` [Patch 1/2] cld: implement dynamic port Jeff Garzik
2009-09-14 18:15 ` Pete Zaitcev
2009-09-15 22:19 ` Jeff Garzik
2009-09-16 19:58 ` Pete Zaitcev
2009-09-16 21:19 ` Jeff Garzik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090902204858.7a3e34a9@redhat.com \
--to=zaitcev@redhat.com \
--cc=hail-devel@vger.kernel.org \
--cc=jeff@garzik.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.