From owner-svn-src-head@FreeBSD.ORG Thu Feb 3 11:39:49 2011 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id CA7581065674; Thu, 3 Feb 2011 11:39:49 +0000 (UTC) (envelope-from pjd@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id B8F618FC19; Thu, 3 Feb 2011 11:39:49 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p13BdnHn044117; Thu, 3 Feb 2011 11:39:49 GMT (envelope-from pjd@svn.freebsd.org) Received: (from pjd@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p13BdnjX044111; Thu, 3 Feb 2011 11:39:49 GMT (envelope-from pjd@svn.freebsd.org) Message-Id: <201102031139.p13BdnjX044111@svn.freebsd.org> From: Pawel Jakub Dawidek Date: Thu, 3 Feb 2011 11:39:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r218218 - head/sbin/hastd X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Feb 2011 11:39:49 -0000 Author: pjd Date: Thu Feb 3 11:39:49 2011 New Revision: 218218 URL: http://svn.freebsd.org/changeset/base/218218 Log: Setup another socketpair between parent and child, so that primary sandboxed worker can ask the main privileged process to connect in worker's behalf and then we can migrate descriptor using this socketpair to worker. This is not really needed now, but will be needed once we start to use capsicum for sandboxing. MFC after: 1 week Modified: head/sbin/hastd/control.c head/sbin/hastd/hast.h head/sbin/hastd/hastd.c head/sbin/hastd/primary.c head/sbin/hastd/secondary.c Modified: head/sbin/hastd/control.c ============================================================================== --- head/sbin/hastd/control.c Thu Feb 3 11:33:32 2011 (r218217) +++ head/sbin/hastd/control.c Thu Feb 3 11:39:49 2011 (r218218) @@ -62,6 +62,10 @@ child_cleanup(struct hast_resource *res) proto_close(res->hr_event); res->hr_event = NULL; } + if (res->hr_conn != NULL) { + proto_close(res->hr_conn); + res->hr_conn = NULL; + } res->hr_workerpid = 0; } Modified: head/sbin/hastd/hast.h ============================================================================== --- head/sbin/hastd/hast.h Thu Feb 3 11:33:32 2011 (r218217) +++ head/sbin/hastd/hast.h Thu Feb 3 11:39:49 2011 (r218218) @@ -182,10 +182,12 @@ struct hast_resource { int hr_previous_role; /* PID of child worker process. 0 - no child. */ pid_t hr_workerpid; - /* Control connection between parent and child. */ + /* Control commands from parent to child. */ struct proto_conn *hr_ctrl; /* Events from child to parent. */ struct proto_conn *hr_event; + /* Connection requests from child to parent. */ + struct proto_conn *hr_conn; /* Activemap structure. */ struct activemap *hr_amp; Modified: head/sbin/hastd/hastd.c ============================================================================== --- head/sbin/hastd/hastd.c Thu Feb 3 11:33:32 2011 (r218217) +++ head/sbin/hastd/hastd.c Thu Feb 3 11:39:49 2011 (r218218) @@ -214,6 +214,19 @@ descriptors_assert(const struct hast_res fd, dtype2str(mode), dtype2str(S_IFSOCK)); break; } + } else if (fd == proto_descriptor(res->hr_conn)) { + if (!isopen) { + snprintf(msg, sizeof(msg), + "Descriptor %d (conn) is closed, but should be open.", + fd); + break; + } + if (!S_ISSOCK(mode)) { + snprintf(msg, sizeof(msg), + "Descriptor %d (conn) is %s, but should be %s.", + fd, dtype2str(mode), dtype2str(S_IFSOCK)); + break; + } } else if (res->hr_role == HAST_ROLE_SECONDARY && fd == proto_descriptor(res->hr_remotein)) { if (!isopen) { @@ -802,6 +815,41 @@ close: } static void +connection_migrate(struct hast_resource *res) +{ + struct proto_conn *conn; + int16_t val = 0; + + if (proto_recv(res->hr_conn, &val, sizeof(val)) < 0) { + pjdlog_errno(LOG_WARNING, + "Unable to receive connection command"); + return; + } + if (proto_client(res->hr_remoteaddr, &conn) < 0) { + val = errno; + pjdlog_errno(LOG_WARNING, + "Unable to create outgoing connection to %s", + res->hr_remoteaddr); + goto out; + } + if (proto_connect(conn, -1) < 0) { + val = errno; + pjdlog_errno(LOG_WARNING, "Unable to connect to %s", + res->hr_remoteaddr); + proto_close(conn); + goto out; + } + val = 0; +out: + if (proto_send(res->hr_conn, &val, sizeof(val)) < 0) { + pjdlog_errno(LOG_WARNING, + "Unable to send reply to connection request"); + } + if (val == 0 && proto_connection_send(res->hr_conn, conn) < 0) + pjdlog_errno(LOG_WARNING, "Unable to send connection"); +} + +static void main_loop(void) { struct hast_resource *res; @@ -858,10 +906,18 @@ main_loop(void) TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { if (res->hr_event == NULL) continue; + PJDLOG_ASSERT(res->hr_conn != NULL); fd = proto_descriptor(res->hr_event); PJDLOG_ASSERT(fd >= 0); FD_SET(fd, &rfds); maxfd = fd > maxfd ? fd : maxfd; + if (res->hr_role == HAST_ROLE_PRIMARY) { + /* Only primary workers asks for connections. */ + fd = proto_descriptor(res->hr_conn); + PJDLOG_ASSERT(fd >= 0); + FD_SET(fd, &rfds); + maxfd = fd > maxfd ? fd : maxfd; + } } PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE); @@ -882,12 +938,20 @@ main_loop(void) TAILQ_FOREACH(res, &cfg->hc_resources, hr_next) { if (res->hr_event == NULL) continue; + PJDLOG_ASSERT(res->hr_conn != NULL); if (FD_ISSET(proto_descriptor(res->hr_event), &rfds)) { if (event_recv(res) == 0) continue; /* The worker process exited? */ proto_close(res->hr_event); res->hr_event = NULL; + proto_close(res->hr_conn); + res->hr_conn = NULL; + continue; + } + if (res->hr_role == HAST_ROLE_PRIMARY && + FD_ISSET(proto_descriptor(res->hr_conn), &rfds)) { + connection_migrate(res); } } } Modified: head/sbin/hastd/primary.c ============================================================================== --- head/sbin/hastd/primary.c Thu Feb 3 11:33:32 2011 (r218217) +++ head/sbin/hastd/primary.c Thu Feb 3 11:39:49 2011 (r218218) @@ -488,6 +488,46 @@ init_local(struct hast_resource *res) exit(EX_NOINPUT); } +static int +primary_connect(struct hast_resource *res, struct proto_conn **connp) +{ + struct proto_conn *conn; + int16_t val; + + val = 1; + if (proto_send(res->hr_conn, &val, sizeof(val)) < 0) { + primary_exit(EX_TEMPFAIL, + "Unable to send connection request to parent"); + } + if (proto_recv(res->hr_conn, &val, sizeof(val)) < 0) { + primary_exit(EX_TEMPFAIL, + "Unable to receive reply to connection request from parent"); + } + if (val != 0) { + errno = val; + pjdlog_errno(LOG_WARNING, "Unable to connect to %s", + res->hr_remoteaddr); + return (-1); + } + if (proto_connection_recv(res->hr_conn, true, &conn) < 0) { + primary_exit(EX_TEMPFAIL, + "Unable to receive connection from parent"); + } + if (proto_connect_wait(conn, HAST_TIMEOUT) < 0) { + pjdlog_errno(LOG_WARNING, "Unable to connect to %s", + res->hr_remoteaddr); + proto_close(conn); + return (-1); + } + /* Error in setting timeout is not critical, but why should it fail? */ + if (proto_timeout(conn, res->hr_timeout) < 0) + pjdlog_errno(LOG_WARNING, "Unable to set connection timeout"); + + *connp = conn; + + return (0); +} + static bool init_remote(struct hast_resource *res, struct proto_conn **inp, struct proto_conn **outp) @@ -508,21 +548,9 @@ init_remote(struct hast_resource *res, s in = out = NULL; errmsg = NULL; - /* Prepare outgoing connection with remote node. */ - if (proto_client(res->hr_remoteaddr, &out) < 0) { - primary_exit(EX_TEMPFAIL, - "Unable to create outgoing connection to %s", - res->hr_remoteaddr); - } - /* Try to connect, but accept failure. */ - if (proto_connect(out, HAST_TIMEOUT) < 0) { - pjdlog_errno(LOG_WARNING, "Unable to connect to %s", - res->hr_remoteaddr); - goto close; - } - /* Error in setting timeout is not critical, but why should it fail? */ - if (proto_timeout(out, res->hr_timeout) < 0) - pjdlog_errno(LOG_WARNING, "Unable to set connection timeout"); + if (primary_connect(res, &out) == -1) + return (false); + /* * First handshake step. * Setup outgoing connection with remote node. @@ -576,20 +604,9 @@ init_remote(struct hast_resource *res, s * Second handshake step. * Setup incoming connection with remote node. */ - if (proto_client(res->hr_remoteaddr, &in) < 0) { - primary_exit(EX_TEMPFAIL, - "Unable to create incoming connection to %s", - res->hr_remoteaddr); - } - /* Try to connect, but accept failure. */ - if (proto_connect(in, HAST_TIMEOUT) < 0) { - pjdlog_errno(LOG_WARNING, "Unable to connect to %s", - res->hr_remoteaddr); + if (primary_connect(res, &in) == -1) goto close; - } - /* Error in setting timeout is not critical, but why should it fail? */ - if (proto_timeout(in, res->hr_timeout) < 0) - pjdlog_errno(LOG_WARNING, "Unable to set connection timeout"); + nvout = nv_alloc(); nv_add_string(nvout, res->hr_name, "resource"); nv_add_uint8_array(nvout, res->hr_token, sizeof(res->hr_token), @@ -792,7 +809,8 @@ hastd_primary(struct hast_resource *res) int error, mode; /* - * Create communication channel between parent and child. + * Create communication channel for sending control commands from + * parent to child. */ if (proto_client("socketpair://", &res->hr_ctrl) < 0) { /* TODO: There's no need for this to be fatal error. */ @@ -801,7 +819,7 @@ hastd_primary(struct hast_resource *res) "Unable to create control sockets between parent and child"); } /* - * Create communication channel between child and parent. + * Create communication channel for sending events from child to parent. */ if (proto_client("socketpair://", &res->hr_event) < 0) { /* TODO: There's no need for this to be fatal error. */ @@ -809,6 +827,16 @@ hastd_primary(struct hast_resource *res) pjdlog_exit(EX_OSERR, "Unable to create event sockets between child and parent"); } + /* + * Create communication channel for sending connection requests from + * child to parent. + */ + if (proto_client("socketpair://", &res->hr_conn) < 0) { + /* TODO: There's no need for this to be fatal error. */ + KEEP_ERRNO((void)pidfile_remove(pfh)); + pjdlog_exit(EX_OSERR, + "Unable to create connection sockets between child and parent"); + } pid = fork(); if (pid < 0) { @@ -821,6 +849,7 @@ hastd_primary(struct hast_resource *res) /* This is parent. */ /* Declare that we are receiver. */ proto_recv(res->hr_event, NULL, 0); + proto_recv(res->hr_conn, NULL, 0); /* Declare that we are sender. */ proto_send(res->hr_ctrl, NULL, 0); res->hr_workerpid = pid; @@ -832,6 +861,7 @@ hastd_primary(struct hast_resource *res) /* Declare that we are sender. */ proto_send(res->hr_event, NULL, 0); + proto_send(res->hr_conn, NULL, 0); /* Declare that we are receiver. */ proto_recv(res->hr_ctrl, NULL, 0); descriptors_cleanup(res); Modified: head/sbin/hastd/secondary.c ============================================================================== --- head/sbin/hastd/secondary.c Thu Feb 3 11:33:32 2011 (r218217) +++ head/sbin/hastd/secondary.c Thu Feb 3 11:39:49 2011 (r218218) @@ -364,6 +364,16 @@ hastd_secondary(struct hast_resource *re pjdlog_exit(EX_OSERR, "Unable to create event sockets between child and parent"); } + /* + * Create communication channel for sending connection requests from + * parent to child. + */ + if (proto_client("socketpair://", &res->hr_conn) < 0) { + /* TODO: There's no need for this to be fatal error. */ + KEEP_ERRNO((void)pidfile_remove(pfh)); + pjdlog_exit(EX_OSERR, + "Unable to create connection sockets between parent and child"); + } pid = fork(); if (pid < 0) { @@ -381,6 +391,7 @@ hastd_secondary(struct hast_resource *re proto_recv(res->hr_event, NULL, 0); /* Declare that we are sender. */ proto_send(res->hr_ctrl, NULL, 0); + proto_send(res->hr_conn, NULL, 0); res->hr_workerpid = pid; return; } @@ -392,6 +403,7 @@ hastd_secondary(struct hast_resource *re proto_send(res->hr_event, NULL, 0); /* Declare that we are receiver. */ proto_recv(res->hr_ctrl, NULL, 0); + proto_recv(res->hr_conn, NULL, 0); descriptors_cleanup(res); descriptors_assert(res, mode);