You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by wr...@apache.org on 2009/05/29 07:49:08 UTC
svn commit: r779848 - in /httpd/mod_ftp/trunk/modules/ftp: ftp_internal.h
ftp_lowportd.c
Author: wrowe
Date: Fri May 29 05:49:07 2009
New Revision: 779848
URL: http://svn.apache.org/viewvc?rev=779848&view=rev
Log:
Add a low numbered port daemon, mod ftp lowportd, which exists for the server
generation and will serve properly formed requests as bound sockets through
a unix domain pipe. We trust sys/un.h to deteremine availability.
This likely needs a bit of refactoring to accomodate msg_accrights if a few
platforms still use this mechanism, however I'm too tired to bother at the
moment and still steamed at deleting this source when at 90% completion.
So it hits subversion in its working form for linux.
Mostly derived from code at mod_cgid, look there if something 'interesting'
is discovered, since the two code bases likely share any issues.
Added:
httpd/mod_ftp/trunk/modules/ftp/ftp_lowportd.c (with props)
Modified:
httpd/mod_ftp/trunk/modules/ftp/ftp_internal.h
Modified: httpd/mod_ftp/trunk/modules/ftp/ftp_internal.h
URL: http://svn.apache.org/viewvc/httpd/mod_ftp/trunk/modules/ftp/ftp_internal.h?rev=779848&r1=779847&r2=779848&view=diff
==============================================================================
--- httpd/mod_ftp/trunk/modules/ftp/ftp_internal.h (original)
+++ httpd/mod_ftp/trunk/modules/ftp/ftp_internal.h Fri May 29 05:49:07 2009
@@ -347,4 +347,20 @@
struct ftp_cmd_entry *next; /* Pointer to the next handler */
};
+/* FTP low-numbered-port allocation daemon
+ *
+ * ftp_lowportd.c
+ */
+/* Lone onfiguration option */
+const char *lowportd_set_socket(cmd_parms *cmd, void *dummy, const char *arg);
+
+#if APR_HAVE_SYS_UN_H
+/* Initialization */
+int lowportd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp);
+int lowportd_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp,
+ server_rec *main_server);
+apr_status_t ftp_request_lowport(apr_socket_t **sock, request_rec *r,
+ apr_sockaddr_t *sa, apr_pool_t *p);
+#endif
+
#endif
Added: httpd/mod_ftp/trunk/modules/ftp/ftp_lowportd.c
URL: http://svn.apache.org/viewvc/httpd/mod_ftp/trunk/modules/ftp/ftp_lowportd.c?rev=779848&view=auto
==============================================================================
--- httpd/mod_ftp/trunk/modules/ftp/ftp_lowportd.c (added)
+++ httpd/mod_ftp/trunk/modules/ftp/ftp_lowportd.c Fri May 29 05:49:07 2009
@@ -0,0 +1,608 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mod_ftp.h"
+#include "ftp_internal.h"
+#include "apr_signal.h"
+#include "ap_listen.h"
+#include "ap_mpm.h"
+#include "unixd.h"
+
+/* The module is enabled by the presence of unix domain sockets */
+#if APR_HAVE_SYS_UN_H
+#include <sys/un.h> /* for sockaddr_un */
+
+#if APR_HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if APR_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+typedef struct lowportd_req_t {
+ pid_t ppid;
+ server_rec *server;
+#if APR_HAVE_IPV6
+ struct sockaddr_in6 sockaddr;
+#else
+ struct sockaddr_in sockaddr;
+#endif
+ size_t sockaddr_len;
+} lowportd_req_t;
+
+static apr_pool_t *pdaemon = NULL;
+static const char *sockname;
+static struct sockaddr_un *daemon_addr;
+static apr_socklen_t daemon_addr_len;
+static pid_t parent_pid;
+static pid_t daemon_pid;
+static int daemon_should_exit = 0;
+
+/* The APR other-child API doesn't tell us how the daemon exited
+ * (SIGSEGV vs. exit(1)). The other-child maintenance function
+ * needs to decide whether to restart the daemon after a failure
+ * based on whether or not it exited due to a fatal startup error
+ * or something that happened at steady-state. This exit status
+ * is unlikely to collide with exit signals.
+ */
+#define DAEMON_STARTUP_ERROR 254
+
+/* DEFAULT_CGID_LISTENBACKLOG controls the max depth on the unix socket's
+ * pending connection queue. If a bunch of cgi requests arrive at about
+ * the same time, connections from httpd threads/processes will back up
+ * in the queue while the cgid process slowly forks off a child to process
+ * each connection on the unix socket. If the queue is too short, the
+ * httpd process will get ECONNREFUSED when trying to connect.
+ */
+#ifndef DEFAULT_CGID_LISTENBACKLOG
+#define DEFAULT_CGID_LISTENBACKLOG 100
+#endif
+
+/* DEFAULT_CONNECT_ATTEMPTS controls how many times we'll try to connect
+ * to the cgi daemon from the thread/process handling the cgi request.
+ * Generally we want to retry when we get ECONNREFUSED since it is
+ * probably because the listen queue is full. We need to try harder so
+ * the client doesn't see it as a 503 error.
+ *
+ * Set this to 0 to continually retry until the connect works or Apache
+ * terminates.
+ */
+#ifndef DEFAULT_CONNECT_ATTEMPTS
+#define DEFAULT_CONNECT_ATTEMPTS 15
+#endif
+
+#define DEFAULT_SOCKET DEFAULT_REL_RUNTIMEDIR "/ftp-lowportd-sock"
+
+/* deal with incomplete reads, writes and signals
+ * assume you really have to read/write buf_size bytes
+ */
+static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size)
+{
+ char *buf = vbuf;
+ int rc;
+ size_t bytes_read = 0;
+
+ do {
+ do {
+ rc = read(fd, buf + bytes_read, buf_size - bytes_read);
+ } while (rc < 0 && errno == EINTR);
+ switch(rc) {
+ case -1:
+ return errno;
+ case 0: /* unexpected */
+ return ECONNRESET;
+ default:
+ bytes_read += rc;
+ }
+ } while (bytes_read < buf_size);
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t sock_write(int fd, const void *buf, size_t buf_size)
+{
+ int rc;
+
+ while (buf_size) {
+ while ((rc = write(fd, buf, buf_size)) < 0)
+ if (errno != EINTR)
+ return errno;
+ buf += rc;
+ buf_size -= rc;
+ }
+ return APR_SUCCESS;
+}
+
+static int connect_to_daemon(int *sdptr, request_rec *r)
+{
+ int sd;
+ int connect_tries = 0;
+ apr_interval_time_t sliding_timer = 100000; /* 100 milliseconds */
+
+ while (1) {
+ ++connect_tries;
+ if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, errno, r,
+ "unable to create socket to ftp low numbered port "
+ "connection daemon after multiple attempts");
+ return errno;
+ }
+ if (connect(sd, (struct sockaddr *)daemon_addr, daemon_addr_len) < 0) {
+ if (errno == ECONNREFUSED
+ && connect_tries < DEFAULT_CONNECT_ATTEMPTS) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, errno, r,
+ "connect #%d to cgi daemon failed, "
+ "sleeping before retry", connect_tries);
+ close(sd);
+ apr_sleep(sliding_timer);
+ if (sliding_timer < apr_time_from_sec(2)) {
+ sliding_timer *= 2;
+ }
+ }
+ else {
+ close(sd);
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, errno, r,
+ "unable to connect to ftp low numbered port "
+ "connection daemon after multiple attempts");
+ return errno;
+ }
+ }
+ else {
+ break; /* we got connected! */
+ }
+ /* gotta try again, but make sure the daemon is still around */
+ if (kill(daemon_pid, 0) != 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, errno, r,
+ "ftp low numbered port daemon is gone! "
+ "Is Apache terminating?");
+ return errno;
+ }
+ }
+ *sdptr = sd;
+ return APR_SUCCESS;
+}
+
+apr_status_t ftp_request_lowport(apr_socket_t **sock, request_rec *r,
+ apr_sockaddr_t *sa, apr_pool_t *p)
+{
+ apr_os_sock_info_t sockinfo = {0};
+ lowportd_req_t req = {0};
+ apr_status_t stat;
+ int sd = -1;
+ struct msghdr msg = {0};
+ struct cmsghdr *cmsg;
+ union {
+ struct cmsghdr align;
+ char ccmsg[CMSG_SPACE(sizeof(*sockinfo.os_sock))];
+ } msgbuf;
+ int one;
+ struct iovec iov = {&one, sizeof(one)};
+
+ msg.msg_control = msgbuf.ccmsg;
+ msg.msg_controllen = sizeof(msgbuf.ccmsg);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if (sa->salen > sizeof(req.sockaddr))
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_EINVAL, r,
+ "ftp low numbered port request; unexpected sa len");
+ return APR_EINVAL;
+ }
+
+ req.ppid = parent_pid;
+ req.server = r->server;
+ req.sockaddr_len = sa->salen;
+ memcpy(&req.sockaddr, &sa->sa, sa->salen);
+
+ if ((stat = connect_to_daemon(&sd, r)) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, stat, r,
+ "ftp low numbered port request; failed to connect");
+ return stat;
+ }
+
+ /* Write the request header */
+ if ((stat = sock_write(sd, &req, sizeof(req))) != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, stat, r,
+ "ftp low numbered port request; failed to send request");
+ close(sd);
+ return stat;
+ }
+
+ while (recvmsg(sd, &msg, 0) == -1)
+ if (errno != EINTR) {
+ stat = errno;
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, stat, r,
+ "ftp low numbered port request; receive failed");
+ close(sd);
+ return stat;
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg || cmsg->cmsg_level != SOL_SOCKET
+ || cmsg->cmsg_type != SCM_RIGHTS) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_EINVAL, r,
+ "ftp low numbered port request; unexpected response");
+ close(sd);
+ return APR_EINVAL;
+ }
+
+ sockinfo.os_sock = (int *)CMSG_DATA(cmsg);
+ sockinfo.family = sa->sa.sin.sin_family;
+ sockinfo.type = SOCK_STREAM;
+ sockinfo.protocol = IPPROTO_TCP;
+ sockinfo.local = (struct sockaddr *)&sa->sa;
+
+ stat = apr_os_sock_make(sock, &sockinfo, p);
+ if (stat != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, stat, r,
+ "ftp low numbered port request; sock_make failed");
+ }
+
+ close(sd);
+ return APR_SUCCESS;
+}
+
+static void daemon_signal_handler(int sig)
+{
+ if (sig == SIGHUP) {
+ ++daemon_should_exit;
+ }
+}
+
+static int lowportd_server(void *data)
+{
+ int sd, sd2, rc;
+ mode_t omask;
+ apr_pool_t *ptrans;
+ server_rec *main_server = data;
+ apr_status_t rv;
+
+ apr_pool_create(&ptrans, pdaemon);
+
+ apr_signal(SIGCHLD, SIG_IGN);
+ apr_signal(SIGHUP, daemon_signal_handler);
+
+ /* Close our copy of the listening sockets */
+ ap_close_listeners();
+
+ if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
+ "Couldn't create unix domain socket");
+ return errno;
+ }
+
+ omask = umask(0077); /* so that only Apache can use socket */
+ rc = bind(sd, (struct sockaddr *)daemon_addr, daemon_addr_len);
+ umask(omask); /* can't fail, so can't clobber errno */
+ if (rc < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
+ "Couldn't bind unix domain socket %s",
+ sockname);
+ return errno;
+ }
+
+ /* Not all flavors of unix use the current umask for AF_UNIX perms */
+ rv = apr_file_perms_set(sockname, APR_FPROT_UREAD|APR_FPROT_UWRITE
+ |APR_FPROT_UEXECUTE);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, main_server,
+ "Couldn't set permissions on unix domain socket %s",
+ sockname);
+ return rv;
+ }
+
+ if (listen(sd, DEFAULT_CGID_LISTENBACKLOG) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
+ "Couldn't listen on unix domain socket");
+ return errno;
+ }
+
+ if (!geteuid()) {
+ if (chown(sockname, ap_unixd_config.user_id, -1) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
+ "Couldn't change owner of unix domain socket %s",
+ sockname);
+ return errno;
+ }
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, main_server,
+ "FTP low numbered port daemon waiting for port requests");
+
+ while (!daemon_should_exit) {
+ apr_proc_t *procnew = NULL;
+ lowportd_req_t req;
+ apr_status_t stat;
+ apr_socklen_t len;
+ struct sockaddr_un unix_addr;
+ server_rec *server;
+ int fd;
+ int one = 1;
+ struct msghdr msg = {0};
+ struct cmsghdr *cmsg;
+ union {
+ struct cmsghdr align;
+ char ccmsg[CMSG_SPACE(sizeof(fd))];
+ } msgbuf;
+ struct iovec iov = {&one, sizeof(one)};
+
+ apr_pool_clear(ptrans);
+
+ len = sizeof(unix_addr);
+ sd2 = accept(sd, (struct sockaddr *)&unix_addr, &len);
+ if (sd2 < 0) {
+#if defined(ENETDOWN)
+ if (errno == ENETDOWN) {
+ /* The network has been shut down, die off with error msg */
+ ++daemon_should_exit;
+ }
+#endif
+ if (errno != EINTR) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno,
+ (server_rec *)data,
+ "FTP Error accepting on lowportd socket");
+ }
+ continue;
+ }
+
+ procnew = apr_pcalloc(ptrans, sizeof(*procnew));
+ stat = sock_read(sd2, &req, sizeof(req));
+ if (stat != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, stat,
+ main_server,
+ "FTP Error reading request on lowportd socket");
+ close(sd2);
+ continue;
+ }
+
+ if (req.ppid != parent_pid) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
+ "FTP low port request received from wrong server "
+ "instance; see FTPLowPortSock directive");
+ close(sd2);
+ continue;
+ }
+
+ for (server = ap_server_conf; server; server = server->next)
+ if (server == req.server)
+ break;
+ if (!server) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
+ "FTP low port request received for invalid server");
+ close(sd2);
+ continue;
+ }
+
+#if APR_HAVE_IPV6
+ fd = socket(req.sockaddr.sin6_family, SOCK_STREAM, APR_PROTO_TCP);
+#else
+ fd = socket(req.sockaddr.sin_family, SOCK_STREAM, APR_PROTO_TCP);
+#endif
+ if (fd < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, server,
+ "FTP low port daemon failed to create socket");
+ close(sd2);
+ continue;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (void*)&one, sizeof(one)) == -1)
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, errno, server,
+ "FTP low port daemon failed to set reuseaddr flag");
+
+ if (bind(fd, (struct sockaddr *)&req.sockaddr, req.sockaddr_len)
+ == -1) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, server,
+ "FTP low port daemon failed to create socket");
+ close(sd2);
+ continue;
+ }
+
+ msg.msg_control = msgbuf.ccmsg;
+ msg.msg_controllen = sizeof(msgbuf.ccmsg);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ *(int*)CMSG_DATA(cmsg) = fd;
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ while (sendmsg(sd2, &msg, 0) == -1)
+ if (errno != EINTR) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, server,
+ "FTP low port daemon; error sending bound fd");
+ break;
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, errno, server,
+ "FTP low port daemon success; sent bound socket fd");
+
+ close(fd);
+ close(sd2);
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, main_server,
+ "FTP low numbered port daemon exiting");
+
+ return -1; /* should be <= 0 to distinguish from startup errors */
+}
+
+static void lowportd_maint(int reason, void *data, apr_wait_t status);
+
+static int lowportd_start(apr_pool_t *p, server_rec *main_server,
+ apr_proc_t *procnew)
+{
+
+ daemon_should_exit = 0; /* clear setting from previous generation */
+ if ((daemon_pid = fork()) < 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
+ "mod_ftp: Couldn't spawn lowportd daemon process");
+ return DECLINED;
+ }
+ else if (daemon_pid == 0) {
+ exit(lowportd_server(main_server) > 0 ? DAEMON_STARTUP_ERROR : -1);
+ }
+ procnew->pid = daemon_pid;
+ procnew->err = procnew->in = procnew->out = NULL;
+ apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
+#if APR_HAS_OTHER_CHILD
+ apr_proc_other_child_register(procnew, lowportd_maint, procnew, NULL, p);
+#endif
+ return OK;
+}
+
+#if APR_HAS_OTHER_CHILD
+static void lowportd_maint(int reason, void *data, apr_wait_t status)
+{
+ apr_proc_t *proc = data;
+ int mpm_state;
+ int stopping;
+
+ switch (reason) {
+ case APR_OC_REASON_DEATH:
+ apr_proc_other_child_unregister(data);
+ /* If apache is not terminating or restarting,
+ * restart the daemon
+ */
+ stopping = 1; /* if MPM doesn't support query,
+ * assume we shouldn't restart daemon
+ */
+ if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state) == APR_SUCCESS &&
+ mpm_state != AP_MPMQ_STOPPING) {
+ stopping = 0;
+ }
+ if (!stopping) {
+ if (status == DAEMON_STARTUP_ERROR) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
+ "lowportd daemon failed to initialize");
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+ "lowportd daemon process died, restarting");
+ lowportd_start(pdaemon, ap_server_conf, proc);
+ }
+ }
+ break;
+ case APR_OC_REASON_RESTART:
+ /* don't do anything; server is stopping or restarting */
+ apr_proc_other_child_unregister(data);
+ break;
+ case APR_OC_REASON_LOST:
+ /* Restart the child daemon process */
+ apr_proc_other_child_unregister(data);
+ lowportd_start(pdaemon, ap_server_conf, proc);
+ break;
+ case APR_OC_REASON_UNREGISTER:
+ /* we get here when pdaemon is cleaned up, which is cleaned
+ * up when pconf gets cleaned up
+ */
+ kill(proc->pid, SIGHUP); /* send signal to daemon to die */
+
+ /* Remove the cgi socket, we must do it here in order to try and
+ * guarantee the same permissions as when the socket was created.
+ */
+ if (unlink(sockname) < 0 && errno != ENOENT) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL,
+ "Couldn't unlink unix domain socket %s",
+ sockname);
+ }
+ break;
+ }
+}
+#endif
+
+int lowportd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
+{
+ sockname = ap_append_pid(pconf, DEFAULT_SOCKET, ".");
+ return OK;
+}
+
+int lowportd_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
+ server_rec *main_server)
+{
+ apr_proc_t *procnew = NULL;
+ int first_time = 0;
+ const char *userdata_key = "lowportd_config";
+ int ret = OK;
+ void *data;
+
+ pdaemon = p;
+
+ apr_pool_userdata_get(&data, userdata_key, main_server->process->pool);
+ if (!data) {
+ first_time = 1;
+ procnew = apr_pcalloc(main_server->process->pool, sizeof(*procnew));
+ procnew->pid = -1;
+ procnew->err = procnew->in = procnew->out = NULL;
+ apr_pool_userdata_set((const void *)procnew, userdata_key,
+ apr_pool_cleanup_null, main_server->process->pool);
+ }
+ else {
+ procnew = data;
+ }
+
+ if (!first_time) {
+ parent_pid = getpid();
+ sockname = ap_server_root_relative(p, sockname);
+
+ daemon_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path)
+ + strlen(sockname);
+ daemon_addr = (struct sockaddr_un *)apr_palloc(p, daemon_addr_len + 1);
+ daemon_addr->sun_family = AF_UNIX;
+ strcpy(daemon_addr->sun_path, sockname);
+
+ ret = lowportd_start(p, main_server, procnew);
+ }
+ return ret;
+}
+
+const char *lowportd_set_socket(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ /* Make sure the pid is appended to the sockname */
+ sockname = ap_append_pid(cmd->pool, arg, ".");
+ sockname = ap_server_root_relative(cmd->pool, sockname);
+
+ if (!sockname) {
+ return apr_pstrcat(cmd->pool, "Invalid FTPLowPortSock path",
+ arg, NULL);
+ }
+
+ return NULL;
+}
+
+#else /* !APR_HAVE_SOCK_UN_H */
+
+const char *lowportd_set_socket(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
+ "FTPLowPortSock directive ignored, this platform does "
+ "not support the low-numbered-port daemon");
+ return NULL;
+}
+
+#endif /* !APR_HAVE_SOCK_UN_H */
Propchange: httpd/mod_ftp/trunk/modules/ftp/ftp_lowportd.c
------------------------------------------------------------------------------
svn:eol-style = native