* [Patch 1/2] cld: implement dynamic port
@ 2009-09-03 2:48 Pete Zaitcev
2009-09-09 19:01 ` Jeff Garzik
0 siblings, 1 reply; 6+ messages in thread
From: Pete Zaitcev @ 2009-09-03 2:48 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Project Hail List
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.
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [Patch 1/2] cld: implement dynamic port
2009-09-03 2:48 [Patch 1/2] cld: implement dynamic port Pete Zaitcev
@ 2009-09-09 19:01 ` Jeff Garzik
2009-09-14 18:15 ` Pete Zaitcev
0 siblings, 1 reply; 6+ messages in thread
From: Jeff Garzik @ 2009-09-09 19:01 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: Project Hail List
On 09/02/2009 10:48 PM, Pete Zaitcev wrote:
> 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>
applied 1-2
though for uniformity, I lean towards thinking that the daemon should
always write a port file, regardless of whether the port was manually
specified or automatically bound.
that enables scripts to work regardless of the locally chosen site policy.
Jeff
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Patch 1/2] cld: implement dynamic port
2009-09-09 19:01 ` Jeff Garzik
@ 2009-09-14 18:15 ` Pete Zaitcev
2009-09-15 22:19 ` Jeff Garzik
0 siblings, 1 reply; 6+ messages in thread
From: Pete Zaitcev @ 2009-09-14 18:15 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Project Hail List
On Wed, 09 Sep 2009 15:01:52 -0400, Jeff Garzik <jeff@garzik.org> wrote:
> though for uniformity, I lean towards thinking that the daemon should
> always write a port file, regardless of whether the port was manually
> specified or automatically bound.
I have a better idea. Let's split PortFile from the enabling
of auto ports. We can have <Port> to with a special string "auto",
and let <PortFile> to be set when static port is configured.
-- Pete
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Patch 1/2] cld: implement dynamic port
2009-09-14 18:15 ` Pete Zaitcev
@ 2009-09-15 22:19 ` Jeff Garzik
2009-09-16 19:58 ` Pete Zaitcev
0 siblings, 1 reply; 6+ messages in thread
From: Jeff Garzik @ 2009-09-15 22:19 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: Project Hail List
On 09/14/2009 02:15 PM, Pete Zaitcev wrote:
> On Wed, 09 Sep 2009 15:01:52 -0400, Jeff Garzik<jeff@garzik.org> wrote:
>
>> though for uniformity, I lean towards thinking that the daemon should
>> always write a port file, regardless of whether the port was manually
>> specified or automatically bound.
>
> I have a better idea. Let's split PortFile from the enabling
> of auto ports. We can have<Port> to with a special string "auto",
> and let<PortFile> to be set when static port is configured.
I think that's fair...
Jeff
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Patch 1/2] cld: implement dynamic port
2009-09-15 22:19 ` Jeff Garzik
@ 2009-09-16 19:58 ` Pete Zaitcev
2009-09-16 21:19 ` Jeff Garzik
0 siblings, 1 reply; 6+ messages in thread
From: Pete Zaitcev @ 2009-09-16 19:58 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Project Hail List
On Tue, 15 Sep 2009 18:19:41 -0400, Jeff Garzik <jeff@garzik.org> wrote:
> On 09/14/2009 02:15 PM, Pete Zaitcev wrote:
> > On Wed, 09 Sep 2009 15:01:52 -0400, Jeff Garzik<jeff@garzik.org> wrote:
> >
> >> though for uniformity, I lean towards thinking that the daemon should
> >> always write a port file, regardless of whether the port was manually
> >> specified or automatically bound.
> >
> > I have a better idea. Let's split PortFile from the enabling
> > of auto ports. We can have<Port> to with a special string "auto",
> > and let<PortFile> to be set when static port is configured.
>
> I think that's fair...
I have posted tabled already, so we have all three in exactly the
same, old scheme now. I'll patch it over. Not sure if I can make it
compatible though... There may be another flag day. Sorry.
I realized my folly when <PortFile>/dev/null</PortFile> appeared.
Probably would've fixed it anyway.
-- Pete
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Patch 1/2] cld: implement dynamic port
2009-09-16 19:58 ` Pete Zaitcev
@ 2009-09-16 21:19 ` Jeff Garzik
0 siblings, 0 replies; 6+ messages in thread
From: Jeff Garzik @ 2009-09-16 21:19 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: Project Hail List
On 09/16/2009 03:58 PM, Pete Zaitcev wrote:
> On Tue, 15 Sep 2009 18:19:41 -0400, Jeff Garzik<jeff@garzik.org> wrote:
>> On 09/14/2009 02:15 PM, Pete Zaitcev wrote:
>>> On Wed, 09 Sep 2009 15:01:52 -0400, Jeff Garzik<jeff@garzik.org> wrote:
>>>
>>>> though for uniformity, I lean towards thinking that the daemon should
>>>> always write a port file, regardless of whether the port was manually
>>>> specified or automatically bound.
>>>
>>> I have a better idea. Let's split PortFile from the enabling
>>> of auto ports. We can have<Port> to with a special string "auto",
>>> and let<PortFile> to be set when static port is configured.
>>
>> I think that's fair...
>
> I have posted tabled already, so we have all three in exactly the
> same, old scheme now. I'll patch it over. Not sure if I can make it
> compatible though... There may be another flag day. Sorry.
Flag days are just fine, this early in the project.
Jeff
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2009-09-16 21:19 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-03 2:48 [Patch 1/2] cld: implement dynamic port Pete Zaitcev
2009-09-09 19:01 ` 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
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.