/* * Copyright (C) 2000, iAgora LLC. * Written by Roger Espel Llima for iAgora LLC, 28-NOV-2000. * * This program is Free Software. You can redistribute and/or modify it * under the terms specified in the file ``LICENSE'', which is part of * the lingerd distribution. (For the impatient: it's an Apache-style * license, without the advertising clause.) * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "httpd.h" #include "http_log.h" #define IN_APACHE #include "li_config.h" /* fd of the open lingerd connection, or -1 if there is none */ static int lingerd_fd = -1; /* time_t of the last time we tried to connect to lingerd */ static int last_try = -1; /* * Try to connect to the lingerd socket at most once every TRY_CONN_PERIOD * seconds; set lingerd_fd if successful. */ void lingerd_connect(void) { struct sockaddr_un sadr; int fd; struct timeval tv; if (lingerd_fd >= 0) return; gettimeofday(&tv, NULL); if (tv.tv_sec < last_try + TRY_CONN_PERIOD) return; last_try = tv.tv_sec; if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) return; sadr.sun_family = AF_UNIX; strncpy(sadr.sun_path, SOCKPATH, sizeof(sadr.sun_path)); sadr.sun_path[sizeof(sadr.sun_path) - 1] = '\0'; if (connect(fd, (struct sockaddr *)&sadr, sizeof(sadr)) < 0) { close(fd); ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL, "Connection to lingerd socket (%s) failed", SOCKPATH); return; } lingerd_fd = fd; } /* * Send an fd to the lingerd daemon. Return 0 for success, -1 for unspecified * failure, and -2 for EPIPE on sendmsg() */ static int real_lingerd_sendfd (int fd) { #ifndef OLD_FD_PASSING static lingerd_cmsghdr l_hdr; struct cmsghdr *hdr = &l_hdr.hdr; #endif struct iovec iov; struct msghdr msg; char aracter = 'Z'; int r; /* If we don't have a lingerd connection, try to open one */ if (lingerd_fd < 0) lingerd_connect(); /* If we *still* don't have a lingerd connection, fail */ if (lingerd_fd < 0) return -1; /* * Create the ancillary data to pass the fd. Also send a single byte * of normal data along with it, or Linux won't wake up the daemon. */ iov.iov_base = &aracter; iov.iov_len = 1; #ifndef OLD_FD_PASSING memset((char *)&l_hdr, 0, sizeof(l_hdr)); #endif memset((char *)&msg, 0, sizeof(msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; #ifdef OLD_FD_PASSING msg.msg_accrights = (char *)&fd; msg.msg_accrightslen = sizeof(fd); #else msg.msg_flags = 0; msg.msg_control = (char *)hdr; msg.msg_controllen = CONTROLLEN; hdr->cmsg_level = SOL_SOCKET; hdr->cmsg_len = CONTROLLEN; hdr->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(hdr) = fd; #endif /* Try to send it */ r = sendmsg(lingerd_fd, &msg, 0); /* Apache already ignores SIGPIPE for us. Yay for Apache. */ if (r < 0) return (errno == EPIPE ? -2 : -1); return 0; } /* * Send an fd to the lingerd daemon. Connect again if the existing * lingerd connection dies on us. */ int lingerd_sendfd (int fd) { int r; if ((r = real_lingerd_sendfd(fd)) != -2) return r; /* close the connection and try again. */ if (lingerd_fd >= 0) close(lingerd_fd); lingerd_fd = -1; /* real_lingerd_fd will do the job of connecting again */ return real_lingerd_sendfd(fd); }