#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
-#include <asm/byteorder.h>
#include <syslog.h>
-
+#include <stdarg.h>
+#include <signal.h>
#include <errno.h>
+#ifdef HAVE_LIBWRAP
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <tcpd.h>
+#endif
+#include <libcfs/portals_utils.h>
#include <portals/api-support.h>
-#include <portals/list.h>
#include <portals/lib-types.h>
+#include <portals/socknal.h>
/* should get this from autoconf somehow */
#ifndef PIDFILE_DIR
#define PIDFILE_DIR "/var/run"
-#endif
+#endif
-#define PROGNAME "acceptor"
+char progname[] = "acceptor";
+char name_port[40]; /* for signal handler */
-void create_pidfile(char *name, int port)
-{
- char pidfile[1024];
- FILE *fp;
-
- snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid",
- PIDFILE_DIR, name, port);
-
- if ((fp = fopen(pidfile, "w"))) {
- fprintf(fp, "%d\n", getpid());
- fclose(fp);
- } else {
- syslog(LOG_ERR, "%s: %s\n", pidfile,
- strerror(errno));
- }
-}
+#ifdef HAVE_LIBWRAP
+/* needed because libwrap declares these as externs */
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
+#endif
-int pidfile_exists(char *name, int port)
+void usage(char *progname)
{
- char pidfile[1024];
-
- snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid",
- PIDFILE_DIR, name, port);
-
- if (!access(pidfile, F_OK)) {
- fprintf(stderr, "%s: exists, acceptor already running.\n",
- pidfile);
- return (1);
- }
- return (0);
+ fprintf(stderr, "usage: %s [-N nal_id] [-p] [-l] port\n\n"
+ " -l\tKeep stdin/stdout open\n"
+ " -p\tAllow connections from non-privileged ports\n", progname);
+ exit (1);
}
-int
-parse_size (int *sizep, char *str)
+void errlog(int level, const char *fmt, ...)
{
- int size;
- char mod[32];
-
- switch (sscanf (str, "%d%1[gGmMkK]", &size, mod))
- {
+ va_list arg;
+ FILE *out;
+
+ switch (level) {
+ case LOG_DEBUG:
+ case LOG_INFO:
+ case LOG_NOTICE:
+ out = stdout;
+ break;
default:
- return (-1);
-
- case 1:
- *sizep = size;
- return (0);
-
- case 2:
- switch (*mod)
- {
- case 'g':
- case 'G':
- *sizep = size << 30;
- return (0);
-
- case 'm':
- case 'M':
- *sizep = size << 20;
- return (0);
-
- case 'k':
- case 'K':
- *sizep = size << 10;
- return (0);
-
- default:
- *sizep = size;
- return (0);
- }
+ out = stderr;
+ break;
}
+ va_start(arg, fmt);
+ fprintf(out, "%s: ", name_port);
+ vfprintf(out, fmt, arg);
+ va_end(arg);
+ va_start(arg, fmt);
+ vsyslog(level, fmt, arg);
+ va_end(arg);
}
-void
-show_connection (int fd, __u32 net_ip, ptl_nid_t nid)
+char *pidfile_name(char *name_port)
{
- struct hostent *h = gethostbyaddr ((char *)&net_ip, sizeof net_ip, AF_INET);
- __u32 host_ip = ntohl (net_ip);
- int rxmem = 0;
- int txmem = 0;
- int nonagle = 0;
- int len;
- char host[1024];
-
- len = sizeof (txmem);
- if (getsockopt (fd, SOL_SOCKET, SO_SNDBUF, &txmem, &len) != 0)
- perror ("Cannot get write buffer size");
-
- len = sizeof (rxmem);
- if (getsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rxmem, &len) != 0)
- perror ("Cannot get read buffer size");
-
- len = sizeof (nonagle);
- if (getsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &nonagle, &len) != 0)
- perror ("Cannot get nagle");
+ static char pidfile[1024];
- if (h == NULL)
- snprintf (host, sizeof(host), "%d.%d.%d.%d", (host_ip >> 24) & 0xff,
- (host_ip >> 16) & 0xff, (host_ip >> 8) & 0xff, host_ip & 0xff);
- else
- snprintf (host, sizeof(host), "%s", h->h_name);
-
- syslog (LOG_INFO, "Accepted host: %s NID: "LPX64" snd: %d rcv %d nagle: %s\n",
- host, nid, txmem, rxmem, nonagle ? "disabled" : "enabled");
+ snprintf(pidfile, sizeof(pidfile), "%s/%s.pid", PIDFILE_DIR, name_port);
+
+ return pidfile;
}
-int
-sock_write (int cfd, void *buffer, int nob)
+int pidfile_create(char *name_port)
{
- while (nob > 0)
- {
- int rc = write (cfd, buffer, nob);
-
- if (rc < 0)
- {
- if (errno == EINTR)
- continue;
-
- return (rc);
+ char *pidfile = pidfile_name(name_port);
+ int fd, rc;
+
+ if ((fd = open(pidfile, O_CREAT | O_WRONLY)) >= 0) {
+ char pid[16];
+ int size = snprintf(pid, sizeof(pid), "%u\n", getpid());
+ if (write(fd, pid, size) != size) {
+ /* hard error or short write */
+ rc = errno ? : EIO;
+ } else {
+ rc = 0;
}
+ close(fd);
+ } else {
+ rc = errno;
+ }
- if (rc == 0)
- {
- fprintf (stderr, "Unexpected zero sock_write\n");
- abort();
- }
+ if (rc)
+ errlog(LOG_ERR, " error creating %s: %s\n",
+ pidfile, strerror(rc));
- nob -= rc;
- buffer = (char *)buffer + nob;
- }
-
- return (0);
+ return rc;
}
-int
-sock_read (int cfd, void *buffer, int nob)
+int pidfile_cleanup(char *name_port)
{
- while (nob > 0)
- {
- int rc = read (cfd, buffer, nob);
-
- if (rc < 0)
- {
- if (errno == EINTR)
- continue;
-
- return (rc);
- }
-
- if (rc == 0) /* EOF */
- {
- errno = ECONNABORTED;
- return (-1);
- }
-
- nob -= rc;
- buffer = (char *)buffer + nob;
- }
-
- return (0);
+ char *pidfile = pidfile_name(name_port);
+ int rc;
+
+ rc = unlink(pidfile);
+ if (rc && errno != -ENOENT)
+ fprintf(stderr, "%s: error removing %s: %s\n",
+ progname, pidfile, strerror(errno));
+ errlog(LOG_NOTICE, "exiting\n");
+
+ return errno;
}
-int
-exchange_nids (int cfd, ptl_nid_t my_nid, ptl_nid_t *peer_nid)
+int pidfile_exists(char *name_port)
{
- int rc;
- ptl_hdr_t hdr;
- ptl_magicversion_t *hmv = (ptl_magicversion_t *)&hdr.dest_nid;
-
- LASSERT (sizeof (*hmv) == sizeof (hdr.dest_nid));
-
- memset (&hdr, 0, sizeof (hdr));
-
- hmv->magic = __cpu_to_le32 (PORTALS_PROTO_MAGIC);
- hmv->version_major = __cpu_to_le16 (PORTALS_PROTO_VERSION_MAJOR);
- hmv->version_minor = __cpu_to_le16 (PORTALS_PROTO_VERSION_MINOR);
-
- hdr.src_nid = __cpu_to_le64 (my_nid);
- hdr.type = __cpu_to_le32 (PTL_MSG_HELLO);
-
- /* Assume there's sufficient socket buffering for a portals HELLO header */
- rc = sock_write (cfd, &hdr, sizeof (hdr));
- if (rc != 0) {
- perror ("Can't send initial HELLO");
- return (-1);
- }
+ char *pidfile = pidfile_name(name_port);
+ FILE *fpid;
+ int pid, rc;
- /* First few bytes down the wire are the portals protocol magic and
- * version, no matter what protocol version we're running. */
-
- rc = sock_read (cfd, hmv, sizeof (*hmv));
- if (rc != 0) {
- perror ("Can't read from peer");
- return (-1);
- }
+ fpid = fopen(pidfile, "r+");
+ if (fpid == NULL) {
+ if (errno == ENOENT)
+ return 0;
- if (__cpu_to_le32 (hmv->magic) != PORTALS_PROTO_MAGIC) {
- fprintf (stderr, "Bad magic %#08x (%#08x expected)\n",
- __cpu_to_le32 (hmv->magic), PORTALS_PROTO_MAGIC);
- return (-1);
+ fprintf(stderr, "%s: error opening %s: %s.\n",
+ progname, pidfile, strerror(errno));
+ return (1);
}
- if (__cpu_to_le16 (hmv->version_major) != PORTALS_PROTO_VERSION_MAJOR ||
- __cpu_to_le16 (hmv->version_minor) != PORTALS_PROTO_VERSION_MINOR) {
- fprintf (stderr, "Incompatible protocol version %d.%d (%d.%d expected)\n",
- __cpu_to_le16 (hmv->version_major),
- __cpu_to_le16 (hmv->version_minor),
- PORTALS_PROTO_VERSION_MAJOR,
- PORTALS_PROTO_VERSION_MINOR);
+ rc = fscanf(fpid, "%i", &pid);
+ fclose(fpid);
+ if (rc != 1) {
+ fprintf(stderr,"%s: %s didn't contain a valid pid, removing.\n",
+ progname, pidfile);
+ goto stale;
}
- /* version 0 sends magic/version as the dest_nid of a 'hello' header,
- * so read the rest of it in now... */
- LASSERT (PORTALS_PROTO_VERSION_MAJOR == 0);
- rc = sock_read (cfd, hmv + 1, sizeof (hdr) - sizeof (*hmv));
- if (rc != 0) {
- perror ("Can't read rest of HELLO hdr");
- return (-1);
+ if (kill(pid, 0) == 0) {
+ fprintf(stderr, "%s: %s exists, acceptor pid %d running.\n",
+ progname, pidfile, pid);
+ return (1);
}
- /* ...and check we got what we expected */
- if (__cpu_to_le32 (hdr.type) != PTL_MSG_HELLO ||
- __cpu_to_le32 (PTL_HDR_LENGTH (&hdr)) != 0) {
- fprintf (stderr, "Expecting a HELLO hdr with 0 payload,"
- " but got type %d with %d payload\n",
- __cpu_to_le32 (hdr.type),
- __cpu_to_le32 (PTL_HDR_LENGTH (&hdr)));
- return (-1);
- }
-
- *peer_nid = __le64_to_cpu (hdr.src_nid);
+ fprintf(stderr, "%s: stale %s exists, pid %d doesn't, removing.\n",
+ progname, pidfile, pid);
+stale:
+ pidfile_cleanup(name_port);
return (0);
}
-void
-usage (char *myname)
+void handler(int sig)
{
- fprintf (stderr, "Usage: %s [-r recv_mem] [-s send_mem] [-n] [-N nal_id] port\n", myname);
- exit (1);
+ exit(sig);
+}
+
+void atexit_handler(void)
+{
+ pidfile_cleanup(name_port);
+}
+
+void show_connection(int fd, __u32 net_ip)
+{
+ static long last_time;
+ static __u32 host_ip;
+ long now = time(0);
+ struct hostent *h;
+ int len;
+ char host[1024];
+
+ /* Don't show repeats for same host, it adds no value */
+ if (host_ip == ntohl(net_ip) && (now - last_time) < 5)
+ return;
+
+ h = gethostbyaddr((char *)&net_ip, sizeof(net_ip), AF_INET);
+ last_time = now;
+ host_ip = ntohl(net_ip);
+
+ if (h == NULL)
+ snprintf(host, sizeof(host), "%d.%d.%d.%d",
+ (host_ip >> 24) & 0xff, (host_ip >> 16) & 0xff,
+ (host_ip >> 8) & 0xff, host_ip & 0xff);
+ else
+ snprintf(host, sizeof(host), "%s", h->h_name);
+
+ syslog(LOG_INFO, "accepted host: %s\n", host);
}
int main(int argc, char **argv)
int o, fd, rc, port, pfd;
struct sockaddr_in srvaddr;
int c;
- int rxmem = 0;
- int txmem = 0;
int noclose = 0;
- int nonagle = 1;
int nal = SOCKNAL;
- int xchg_nids = 0;
- int bind_irq = 0;
-
- while ((c = getopt (argc, argv, "N:r:s:nlxi")) != -1)
- switch (c)
- {
- case 'r':
- if (parse_size (&rxmem, optarg) != 0 || rxmem < 0)
- usage (argv[0]);
- break;
-
- case 's':
- if (parse_size (&txmem, optarg) != 0 || txmem < 0)
- usage (argv[0]);
- break;
+ int rport;
+ int require_privports = 1;
- case 'n':
- nonagle = 0;
+ while ((c = getopt (argc, argv, "N:lp")) != -1) {
+ switch (c) {
+ case 'N':
+ if (sscanf(optarg, "%d", &nal) != 1 ||
+ nal < 0 || nal > NAL_MAX_NR)
+ usage(argv[0]);
break;
-
case 'l':
noclose = 1;
break;
-
- case 'x':
- xchg_nids = 1;
- break;
-
- case 'i':
- bind_irq = 1;
- break;
-
- case 'N':
- if (parse_size(&nal, optarg) != 0 ||
- nal < 0 || nal > NAL_MAX_NR)
- usage(argv[0]);
+ case 'p':
+ require_privports = 0;
break;
-
default:
usage (argv[0]);
break;
}
+ }
if (optind >= argc)
usage (argv[0]);
port = atol(argv[optind++]);
- if (pidfile_exists(PROGNAME, port))
- exit(1);
+ snprintf(name_port, sizeof(name_port) - 1, "%s-%d", progname, port);
+ if (pidfile_exists(name_port))
+ return(EEXIST);
+ openlog(name_port, LOG_PID, LOG_DAEMON);
memset(&srvaddr, 0, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
- perror("opening socket");
- exit(1);
+ rc = errno;
+ errlog(LOG_ERR, "error opening socket: %s\n", strerror(errno));
+ return(rc);
}
o = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o))) {
- perror("Cannot set REUSEADDR socket opt");
- exit(1);
- }
-
- if (nonagle)
- {
- o = 1;
- rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &o, sizeof (o));
- if (rc != 0)
- {
- perror ("Cannot disable nagle");
- exit (1);
- }
+ rc = errno;
+ errlog(LOG_ERR, "cannot set REUSEADDR socket opt: %s\n",
+ strerror(errno));
+ return(rc);
}
- if (txmem != 0)
- {
- rc = setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &txmem, sizeof (txmem));
- if (rc != 0)
- {
- perror ("Cannot set write buffer size");
- exit (1);
- }
- }
-
- if (rxmem != 0)
- {
- rc = setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rxmem, sizeof (rxmem));
- if (rc != 0)
- {
- perror ("Cannot set read buffer size");
- exit (1);
- }
- }
-
rc = bind(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
- if ( rc == -1 ) {
- perror("bind: ");
- exit(1);
+ if (rc == -1) {
+ rc = errno;
+ errlog(LOG_ERR, "error binding to socket: %s\n",
+ strerror(errno));
+ return(rc);
}
if (listen(fd, 127)) {
+ rc = errno;
perror("listen: ");
- exit(1);
+ return(rc);
}
- fprintf(stderr, "listening on port %d\n", port);
+ printf("listening on port %d\n", port);
pfd = open("/dev/portals", O_RDWR);
- if ( pfd < 0 ) {
- perror("opening portals device");
- exit(1);
+ if (pfd < 0) {
+ rc = errno;
+ errlog(LOG_ERR, "opening portals device: %s\n",strerror(errno));
+ return(rc);
}
- rc = daemon(1, noclose);
+ rc = daemon(0, noclose);
if (rc < 0) {
- perror("daemon(): ");
- exit(1);
+ rc = errno;
+ errlog(LOG_ERR, "error daemonizing: %s\n", strerror(errno));
+ return(rc);
}
- openlog(PROGNAME, LOG_PID, LOG_DAEMON);
- syslog(LOG_INFO, "started, listening on port %d\n", port);
- create_pidfile(PROGNAME, port);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, handler);
+ signal(SIGQUIT, handler);
+ signal(SIGTERM, handler);
+
+ errlog(LOG_NOTICE, "started, listening on port %d\n", port);
+ if (pidfile_create(name_port) == 0)
+ atexit(atexit_handler);
while (1) {
struct sockaddr_in clntaddr;
int len = sizeof(clntaddr);
int cfd;
struct portal_ioctl_data data;
- ptl_nid_t peer_nid;
-
+ struct portals_cfg pcfg;
+#ifdef HAVE_LIBWRAP
+ struct request_info request;
+#endif
+ char addrstr[INET_ADDRSTRLEN];
+
cfd = accept(fd, (struct sockaddr *)&clntaddr, &len);
- if ( cfd < 0 ) {
- perror("accept");
- exit(0);
- continue;
+ if (cfd < 0) {
+ errlog(LOG_ERR, "error accepting connection: %s\n",
+ strerror(errno));
+ break;
+ //continue;
}
- if (!xchg_nids)
- peer_nid = ntohl (clntaddr.sin_addr.s_addr); /* HOST byte order */
- else
- {
- PORTAL_IOC_INIT (data);
- data.ioc_nal = nal;
- rc = ioctl (pfd, IOC_PORTAL_GET_NID, &data);
- if (rc < 0)
- {
- perror ("Can't get my NID");
- close (cfd);
- continue;
- }
-
- rc = exchange_nids (cfd, data.ioc_nid, &peer_nid);
- if (rc != 0)
- {
- close (cfd);
- continue;
- }
+ inet_ntop(AF_INET, &clntaddr.sin_addr, addrstr,INET_ADDRSTRLEN);
+#ifdef HAVE_LIBWRAP
+ /* libwrap access control */
+ request_init(&request, RQ_DAEMON, "lustre", RQ_FILE, cfd, 0);
+ sock_host(&request);
+ if (!hosts_access(&request)) {
+ errlog(LOG_WARNING, "unauthorized access from %s:%hd\n",
+ addrstr, ntohs(clntaddr.sin_port));
+ close (cfd);
+ continue;
+ }
+#endif
+
+ if (require_privports &&
+ ntohs(clntaddr.sin_port) >= IPPORT_RESERVED) {
+ errlog(LOG_ERR,
+ "closing non-privileged connection from %s:%d\n",
+ addrstr, ntohs(clntaddr.sin_port));
+ rc = close(cfd);
+ if (rc)
+ perror ("close un-privileged client failed");
+ continue;
}
- show_connection (cfd, clntaddr.sin_addr.s_addr, peer_nid);
-
+ show_connection (cfd, clntaddr.sin_addr.s_addr);
+
+ PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
+ pcfg.pcfg_nal = nal;
+ pcfg.pcfg_fd = cfd;
+ pcfg.pcfg_misc = SOCKNAL_CONN_NONE; /* == incoming connection */
+
PORTAL_IOC_INIT(data);
- data.ioc_fd = cfd;
- data.ioc_nal = nal;
- data.ioc_nal_cmd = NAL_CMD_REGISTER_PEER_FD;
- data.ioc_nid = peer_nid;
- data.ioc_flags = bind_irq;
-
- if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
- perror("ioctl failed");
+ data.ioc_pbuf1 = (char*)&pcfg;
+ data.ioc_plen1 = sizeof(pcfg);
+ if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
+ errlog(LOG_ERR, "portals ioctl failed for %s: %s\n",
+ addrstr, strerror(errno));
} else {
- printf("client registered\n");
+ errlog(LOG_DEBUG, "client %s registered\n", addrstr);
}
rc = close(cfd);
if (rc)
- perror ("close failed");
+ perror("close failed");
}
closelog();
- exit(0);
+ return (0);
}