+ DECL_MSG_CMSG(msg);
+ struct cmsghdr *h= 0;
+ ssize_t rs= recvmsg(fd, &msg, MSG_DONTWAIT);
+ if (rs >= 0) h= CMSG_FIRSTHDR(&msg);
+ if (!h) {
+ int status;
+ pid_t got= waitpid(connecting_child, &status, WNOHANG);
+ if (got != -1) {
+ assert(got==connecting_child);
+ connecting_child= 0;
+ if (WIFEXITED(status) &&
+ (WEXITSTATUS(status) != 0
+ WEXITSTATUS(status) != CHILD_ESTATUS_STREAM &&
+ WEXITSTATUS(status) != CHILD_ESTATUS_NOSTREAM)) {
+ /* child already reported the problem */
+ } else if (WIFSIGNALED(status) && WTERMSIG(status) == SIGALARM) {
+ warn("connect: connection attempt timed out");
+ } else if (!WIFEXITED(status)) {
+ report_child_status("connect", status);
+ /* that's probably the root cause then */
+ }
+ } else {
+ /* child is still running apparently, report the socket problem */
+ if (rs < 0)
+ syswarn("connect: read from child socket failed");
+ else if (e == OOP_EXCEPTIONN)
+ warn("connect: unexpected exception on child socket");
+ else
+ warn("connect: unexpected EOF on child socket");
+ }
+ goto x;
+ }
+
+#define CHK(field, val) \
+ if (h->cmsg_##field != val) { \
+ die("connect: child sent cmsg with cmsg_" #field "=%d, expected %d"); \
+ goto x; \
+ }
+ CHK(level, SOL_SOCKET);
+ CHK(type, SCM_RIGHTS);
+ CHK(len, CMSG_LEN(sizeof(conn-b>fd)));
+#undef CHK
+
+ if (CMSG_NXTHDR,&msg,h) { die("connect: child sent many cmsgs"); goto x; }
+
+ memcpy(&conn->fd, CMSG_DATA(h), sizeof(conn->fd));
+
+ pid_t got= waitpid(connecting_child, &status, 0);
+ if (got==-1) sysdie("connect: real wait for child");
+ assert(got == connecting_child);
+ connecting_child= 0;
+
+ if (!WIFEXITED(status)) { report_child_status("connect",status); goto x; }
+ int es= WEXITSTATUS(status);
+ switch (es) {
+ case CHILD_ESTATUS_STREAM: conn->stream= 1; break;
+ case CHILD_ESTATUS_NOSTREAM: conn->stream= 0; break;
+ default:
+ die("connect: child gave unexpected exit status %d", es);
+ }
+
+ set nonblocking;
+
+ /* Phew! */
+ LIST_ADDHEAD(idle, conn);
+ notice(CN "connected %s", conn->fd, conn->stream ? "streaming" : "plain");
+ connect_attempt_discard();
+ process_queue();
+ return 0;
+
+ x:
+ if (conn) {
+ perhaps_close(&conn->fd);
+ free(conn);
+ }
+ connect_attempt_discard();
+}
+
+static void connect_start() {
+ assert(!connecting_sockets[0]);
+ assert(!connecting_sockets[1]);
+ assert(!connecting_child);
+
+ notice("starting connection attempt");
+
+ r= socketpair(AF_UNIX, SOCK_STREAM, 0, connecting_sockets);
+ if (r) { syswarn("connect: cannot create socketpair for child"); goto x; }
+