1d1d669bdSPawel Jakub Dawidek /*- 2d1d669bdSPawel Jakub Dawidek * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3d1d669bdSPawel Jakub Dawidek * All rights reserved. 4d1d669bdSPawel Jakub Dawidek * 5d1d669bdSPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 6d1d669bdSPawel Jakub Dawidek * modification, are permitted provided that the following conditions 7d1d669bdSPawel Jakub Dawidek * are met: 8d1d669bdSPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 9d1d669bdSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 10d1d669bdSPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 11d1d669bdSPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 12d1d669bdSPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 13d1d669bdSPawel Jakub Dawidek * 14d1d669bdSPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15d1d669bdSPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16d1d669bdSPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17d1d669bdSPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18d1d669bdSPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19d1d669bdSPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20d1d669bdSPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21d1d669bdSPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22d1d669bdSPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23d1d669bdSPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24d1d669bdSPawel Jakub Dawidek * SUCH DAMAGE. 25d1d669bdSPawel Jakub Dawidek * 26d1d669bdSPawel Jakub Dawidek * $FreeBSD$ 27d1d669bdSPawel Jakub Dawidek */ 28d1d669bdSPawel Jakub Dawidek 29d1d669bdSPawel Jakub Dawidek #include <stdio.h> 30d1d669bdSPawel Jakub Dawidek #include <stdlib.h> 31d1d669bdSPawel Jakub Dawidek #include <stdint.h> 32d1d669bdSPawel Jakub Dawidek #include <unistd.h> 33d1d669bdSPawel Jakub Dawidek #include <fcntl.h> 347be67fe3SPawel Jakub Dawidek #include <pthread.h> 35d1d669bdSPawel Jakub Dawidek #include <sys/param.h> 36d1d669bdSPawel Jakub Dawidek #include <sys/queue.h> 37d1d669bdSPawel Jakub Dawidek #include <sys/endian.h> 38d1d669bdSPawel Jakub Dawidek #include <sys/socket.h> 39d1d669bdSPawel Jakub Dawidek #include <sys/ioctl.h> 40d1d669bdSPawel Jakub Dawidek #include <sys/stat.h> 41b34d2de0SBruce Evans #include <sys/time.h> 42d1d669bdSPawel Jakub Dawidek #include <sys/disk.h> 43d1d669bdSPawel Jakub Dawidek #include <sys/bio.h> 44d1d669bdSPawel Jakub Dawidek #include <netinet/in.h> 45d1d669bdSPawel Jakub Dawidek #include <netinet/tcp.h> 46d1d669bdSPawel Jakub Dawidek #include <arpa/inet.h> 47d1d669bdSPawel Jakub Dawidek #include <signal.h> 487be67fe3SPawel Jakub Dawidek #include <assert.h> 49d1d669bdSPawel Jakub Dawidek #include <err.h> 50d1d669bdSPawel Jakub Dawidek #include <errno.h> 51d1d669bdSPawel Jakub Dawidek #include <string.h> 52d1d669bdSPawel Jakub Dawidek #include <libgen.h> 53d1d669bdSPawel Jakub Dawidek #include <syslog.h> 54d1d669bdSPawel Jakub Dawidek #include <stdarg.h> 55d1d669bdSPawel Jakub Dawidek 56d1d669bdSPawel Jakub Dawidek #include "ggate.h" 57d1d669bdSPawel Jakub Dawidek 58d1d669bdSPawel Jakub Dawidek 597be67fe3SPawel Jakub Dawidek #define GGATED_EXPORT_FILE "/etc/gg.exports" 60d1d669bdSPawel Jakub Dawidek 617be67fe3SPawel Jakub Dawidek struct ggd_connection { 627be67fe3SPawel Jakub Dawidek off_t c_mediasize; 6315c7f46bSPawel Jakub Dawidek unsigned c_sectorsize; 647be67fe3SPawel Jakub Dawidek unsigned c_flags; /* flags (RO/RW) */ 657be67fe3SPawel Jakub Dawidek int c_diskfd; 667be67fe3SPawel Jakub Dawidek int c_sendfd; 677be67fe3SPawel Jakub Dawidek int c_recvfd; 687be67fe3SPawel Jakub Dawidek time_t c_birthtime; 697be67fe3SPawel Jakub Dawidek char *c_path; 707be67fe3SPawel Jakub Dawidek uint64_t c_token; 717be67fe3SPawel Jakub Dawidek in_addr_t c_srcip; 727be67fe3SPawel Jakub Dawidek LIST_ENTRY(ggd_connection) c_next; 737be67fe3SPawel Jakub Dawidek }; 74d1d669bdSPawel Jakub Dawidek 757be67fe3SPawel Jakub Dawidek struct ggd_request { 767be67fe3SPawel Jakub Dawidek struct g_gate_hdr r_hdr; 777be67fe3SPawel Jakub Dawidek char *r_data; 787be67fe3SPawel Jakub Dawidek TAILQ_ENTRY(ggd_request) r_next; 797be67fe3SPawel Jakub Dawidek }; 807be67fe3SPawel Jakub Dawidek #define r_cmd r_hdr.gh_cmd 817be67fe3SPawel Jakub Dawidek #define r_offset r_hdr.gh_offset 827be67fe3SPawel Jakub Dawidek #define r_length r_hdr.gh_length 837be67fe3SPawel Jakub Dawidek #define r_error r_hdr.gh_error 847be67fe3SPawel Jakub Dawidek 857be67fe3SPawel Jakub Dawidek struct ggd_export { 86d1d669bdSPawel Jakub Dawidek char *e_path; /* path to device/file */ 87d1d669bdSPawel Jakub Dawidek in_addr_t e_ip; /* remote IP address */ 88d1d669bdSPawel Jakub Dawidek in_addr_t e_mask; /* IP mask */ 89d1d669bdSPawel Jakub Dawidek unsigned e_flags; /* flags (RO/RW) */ 907be67fe3SPawel Jakub Dawidek SLIST_ENTRY(ggd_export) e_next; 91d1d669bdSPawel Jakub Dawidek }; 927be67fe3SPawel Jakub Dawidek 937be67fe3SPawel Jakub Dawidek static const char *exports_file = GGATED_EXPORT_FILE; 947be67fe3SPawel Jakub Dawidek static int got_sighup = 0; 957be67fe3SPawel Jakub Dawidek in_addr_t bindaddr; 967be67fe3SPawel Jakub Dawidek 977be67fe3SPawel Jakub Dawidek static TAILQ_HEAD(, ggd_request) inqueue = TAILQ_HEAD_INITIALIZER(inqueue); 987be67fe3SPawel Jakub Dawidek static TAILQ_HEAD(, ggd_request) outqueue = TAILQ_HEAD_INITIALIZER(outqueue); 997be67fe3SPawel Jakub Dawidek pthread_mutex_t inqueue_mtx, outqueue_mtx; 1007be67fe3SPawel Jakub Dawidek pthread_cond_t inqueue_cond, outqueue_cond; 1017be67fe3SPawel Jakub Dawidek 1027be67fe3SPawel Jakub Dawidek static SLIST_HEAD(, ggd_export) exports = SLIST_HEAD_INITIALIZER(&exports); 1037be67fe3SPawel Jakub Dawidek static LIST_HEAD(, ggd_connection) connections = LIST_HEAD_INITIALIZER(&connection); 1047be67fe3SPawel Jakub Dawidek 1057be67fe3SPawel Jakub Dawidek static void *recv_thread(void *arg); 1067be67fe3SPawel Jakub Dawidek static void *disk_thread(void *arg); 1077be67fe3SPawel Jakub Dawidek static void *send_thread(void *arg); 108d1d669bdSPawel Jakub Dawidek 109d1d669bdSPawel Jakub Dawidek static void 110d1d669bdSPawel Jakub Dawidek usage(void) 111d1d669bdSPawel Jakub Dawidek { 112d1d669bdSPawel Jakub Dawidek 113d1d669bdSPawel Jakub Dawidek fprintf(stderr, "usage: %s [-nv] [-a address] [-p port] [-R rcvbuf] " 114d1d669bdSPawel Jakub Dawidek "[-S sndbuf] [exports file]\n", getprogname()); 115d1d669bdSPawel Jakub Dawidek exit(EXIT_FAILURE); 116d1d669bdSPawel Jakub Dawidek } 117d1d669bdSPawel Jakub Dawidek 118d1d669bdSPawel Jakub Dawidek static char * 119d1d669bdSPawel Jakub Dawidek ip2str(in_addr_t ip) 120d1d669bdSPawel Jakub Dawidek { 121d1d669bdSPawel Jakub Dawidek static char sip[16]; 122d1d669bdSPawel Jakub Dawidek 123d1d669bdSPawel Jakub Dawidek snprintf(sip, sizeof(sip), "%u.%u.%u.%u", 124d1d669bdSPawel Jakub Dawidek ((ip >> 24) & 0xff), 125d1d669bdSPawel Jakub Dawidek ((ip >> 16) & 0xff), 126d1d669bdSPawel Jakub Dawidek ((ip >> 8) & 0xff), 127d1d669bdSPawel Jakub Dawidek (ip & 0xff)); 128d1d669bdSPawel Jakub Dawidek return (sip); 129d1d669bdSPawel Jakub Dawidek } 130d1d669bdSPawel Jakub Dawidek 131d1d669bdSPawel Jakub Dawidek static in_addr_t 132d1d669bdSPawel Jakub Dawidek countmask(unsigned m) 133d1d669bdSPawel Jakub Dawidek { 134d1d669bdSPawel Jakub Dawidek in_addr_t mask; 135d1d669bdSPawel Jakub Dawidek 136d1d669bdSPawel Jakub Dawidek if (m == 0) { 137d1d669bdSPawel Jakub Dawidek mask = 0x0; 138d1d669bdSPawel Jakub Dawidek } else { 139d1d669bdSPawel Jakub Dawidek mask = 1 << (32 - m); 140d1d669bdSPawel Jakub Dawidek mask--; 141d1d669bdSPawel Jakub Dawidek mask = ~mask; 142d1d669bdSPawel Jakub Dawidek } 143d1d669bdSPawel Jakub Dawidek return (mask); 144d1d669bdSPawel Jakub Dawidek } 145d1d669bdSPawel Jakub Dawidek 146d1d669bdSPawel Jakub Dawidek static void 147d1d669bdSPawel Jakub Dawidek line_parse(char *line, unsigned lineno) 148d1d669bdSPawel Jakub Dawidek { 1497be67fe3SPawel Jakub Dawidek struct ggd_export *ex; 150d1d669bdSPawel Jakub Dawidek char *word, *path, *sflags; 151d1d669bdSPawel Jakub Dawidek unsigned flags, i, vmask; 152d1d669bdSPawel Jakub Dawidek in_addr_t ip, mask; 153d1d669bdSPawel Jakub Dawidek 154d1d669bdSPawel Jakub Dawidek ip = mask = flags = vmask = 0; 155d1d669bdSPawel Jakub Dawidek path = NULL; 156d1d669bdSPawel Jakub Dawidek sflags = NULL; 157d1d669bdSPawel Jakub Dawidek 158d1d669bdSPawel Jakub Dawidek for (i = 0, word = strtok(line, " \t"); word != NULL; 159d1d669bdSPawel Jakub Dawidek i++, word = strtok(NULL, " \t")) { 160d1d669bdSPawel Jakub Dawidek switch (i) { 161d1d669bdSPawel Jakub Dawidek case 0: /* IP address or host name */ 162d1d669bdSPawel Jakub Dawidek ip = g_gate_str2ip(strsep(&word, "/")); 163d1d669bdSPawel Jakub Dawidek if (ip == INADDR_NONE) { 164d1d669bdSPawel Jakub Dawidek g_gate_xlog("Invalid IP/host name at line %u.", 165d1d669bdSPawel Jakub Dawidek lineno); 166d1d669bdSPawel Jakub Dawidek } 167d1d669bdSPawel Jakub Dawidek ip = ntohl(ip); 168d1d669bdSPawel Jakub Dawidek if (word == NULL) 169d1d669bdSPawel Jakub Dawidek vmask = 32; 170d1d669bdSPawel Jakub Dawidek else { 171d1d669bdSPawel Jakub Dawidek errno = 0; 172d1d669bdSPawel Jakub Dawidek vmask = strtoul(word, NULL, 10); 173d1d669bdSPawel Jakub Dawidek if (vmask == 0 && errno != 0) { 174d1d669bdSPawel Jakub Dawidek g_gate_xlog("Invalid IP mask value at " 175d1d669bdSPawel Jakub Dawidek "line %u.", lineno); 176d1d669bdSPawel Jakub Dawidek } 177d1d669bdSPawel Jakub Dawidek if ((unsigned)vmask > 32) { 178d1d669bdSPawel Jakub Dawidek g_gate_xlog("Invalid IP mask value at line %u.", 179d1d669bdSPawel Jakub Dawidek lineno); 180d1d669bdSPawel Jakub Dawidek } 181d1d669bdSPawel Jakub Dawidek } 182d1d669bdSPawel Jakub Dawidek mask = countmask(vmask); 183d1d669bdSPawel Jakub Dawidek break; 184d1d669bdSPawel Jakub Dawidek case 1: /* flags */ 185d1d669bdSPawel Jakub Dawidek if (strcasecmp("rd", word) == 0 || 186d1d669bdSPawel Jakub Dawidek strcasecmp("ro", word) == 0) { 187d1d669bdSPawel Jakub Dawidek flags = O_RDONLY; 188d1d669bdSPawel Jakub Dawidek } else if (strcasecmp("wo", word) == 0) { 189d1d669bdSPawel Jakub Dawidek flags = O_WRONLY; 190d1d669bdSPawel Jakub Dawidek } else if (strcasecmp("rw", word) == 0) { 191d1d669bdSPawel Jakub Dawidek flags = O_RDWR; 192d1d669bdSPawel Jakub Dawidek } else { 193d1d669bdSPawel Jakub Dawidek g_gate_xlog("Invalid value in flags field at " 194d1d669bdSPawel Jakub Dawidek "line %u.", lineno); 195d1d669bdSPawel Jakub Dawidek } 196d1d669bdSPawel Jakub Dawidek sflags = word; 197d1d669bdSPawel Jakub Dawidek break; 198d1d669bdSPawel Jakub Dawidek case 2: /* path */ 199d1d669bdSPawel Jakub Dawidek if (strlen(word) >= MAXPATHLEN) { 200d1d669bdSPawel Jakub Dawidek g_gate_xlog("Path too long at line %u. ", 201d1d669bdSPawel Jakub Dawidek lineno); 202d1d669bdSPawel Jakub Dawidek } 203d1d669bdSPawel Jakub Dawidek path = word; 204d1d669bdSPawel Jakub Dawidek break; 205d1d669bdSPawel Jakub Dawidek default: 206d1d669bdSPawel Jakub Dawidek g_gate_xlog("Too many arguments at line %u. ", lineno); 207d1d669bdSPawel Jakub Dawidek } 208d1d669bdSPawel Jakub Dawidek } 209d1d669bdSPawel Jakub Dawidek if (i != 3) 210d1d669bdSPawel Jakub Dawidek g_gate_xlog("Too few arguments at line %u.", lineno); 211d1d669bdSPawel Jakub Dawidek 212d1d669bdSPawel Jakub Dawidek ex = malloc(sizeof(*ex)); 213d1d669bdSPawel Jakub Dawidek if (ex == NULL) 214032de3f9SOleksandr Tymoshenko g_gate_xlog("Not enough memory."); 215d1d669bdSPawel Jakub Dawidek ex->e_path = strdup(path); 216d1d669bdSPawel Jakub Dawidek if (ex->e_path == NULL) 217032de3f9SOleksandr Tymoshenko g_gate_xlog("Not enough memory."); 218d1d669bdSPawel Jakub Dawidek 219d1d669bdSPawel Jakub Dawidek /* Made 'and' here. */ 220d1d669bdSPawel Jakub Dawidek ex->e_ip = (ip & mask); 221d1d669bdSPawel Jakub Dawidek ex->e_mask = mask; 222d1d669bdSPawel Jakub Dawidek ex->e_flags = flags; 223d1d669bdSPawel Jakub Dawidek 2247be67fe3SPawel Jakub Dawidek SLIST_INSERT_HEAD(&exports, ex, e_next); 225d1d669bdSPawel Jakub Dawidek 226d1d669bdSPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Added %s/%u %s %s to exports list.", 227d1d669bdSPawel Jakub Dawidek ip2str(ex->e_ip), vmask, path, sflags); 228d1d669bdSPawel Jakub Dawidek } 229d1d669bdSPawel Jakub Dawidek 230d1d669bdSPawel Jakub Dawidek static void 231d1d669bdSPawel Jakub Dawidek exports_clear(void) 232d1d669bdSPawel Jakub Dawidek { 2337be67fe3SPawel Jakub Dawidek struct ggd_export *ex; 234d1d669bdSPawel Jakub Dawidek 2357be67fe3SPawel Jakub Dawidek while (!SLIST_EMPTY(&exports)) { 2367be67fe3SPawel Jakub Dawidek ex = SLIST_FIRST(&exports); 2377be67fe3SPawel Jakub Dawidek SLIST_REMOVE_HEAD(&exports, e_next); 238d1d669bdSPawel Jakub Dawidek free(ex); 239d1d669bdSPawel Jakub Dawidek } 240d1d669bdSPawel Jakub Dawidek } 241d1d669bdSPawel Jakub Dawidek 242d1d669bdSPawel Jakub Dawidek #define EXPORTS_LINE_SIZE 2048 243d1d669bdSPawel Jakub Dawidek static void 244d1d669bdSPawel Jakub Dawidek exports_get(void) 245d1d669bdSPawel Jakub Dawidek { 246d1d669bdSPawel Jakub Dawidek char buf[EXPORTS_LINE_SIZE], *line; 247d1d669bdSPawel Jakub Dawidek unsigned lineno = 0, objs = 0, len; 248d1d669bdSPawel Jakub Dawidek FILE *fd; 249d1d669bdSPawel Jakub Dawidek 250d1d669bdSPawel Jakub Dawidek exports_clear(); 251d1d669bdSPawel Jakub Dawidek 2527be67fe3SPawel Jakub Dawidek fd = fopen(exports_file, "r"); 253d1d669bdSPawel Jakub Dawidek if (fd == NULL) { 2547be67fe3SPawel Jakub Dawidek g_gate_xlog("Cannot open exports file (%s): %s.", exports_file, 255d1d669bdSPawel Jakub Dawidek strerror(errno)); 256d1d669bdSPawel Jakub Dawidek } 257d1d669bdSPawel Jakub Dawidek 2587be67fe3SPawel Jakub Dawidek g_gate_log(LOG_INFO, "Reading exports file (%s).", exports_file); 259d1d669bdSPawel Jakub Dawidek 260d1d669bdSPawel Jakub Dawidek for (;;) { 261d1d669bdSPawel Jakub Dawidek if (fgets(buf, sizeof(buf), fd) == NULL) { 262d1d669bdSPawel Jakub Dawidek if (feof(fd)) 263d1d669bdSPawel Jakub Dawidek break; 264d1d669bdSPawel Jakub Dawidek 265d1d669bdSPawel Jakub Dawidek g_gate_xlog("Error while reading exports file: %s.", 266d1d669bdSPawel Jakub Dawidek strerror(errno)); 267d1d669bdSPawel Jakub Dawidek } 268d1d669bdSPawel Jakub Dawidek 269d1d669bdSPawel Jakub Dawidek /* Increase line count. */ 270d1d669bdSPawel Jakub Dawidek lineno++; 271d1d669bdSPawel Jakub Dawidek 272d1d669bdSPawel Jakub Dawidek /* Skip spaces and tabs. */ 273d1d669bdSPawel Jakub Dawidek for (line = buf; *line == ' ' || *line == '\t'; ++line) 274d1d669bdSPawel Jakub Dawidek ; 275d1d669bdSPawel Jakub Dawidek 276d1d669bdSPawel Jakub Dawidek /* Empty line, comment or empty line at the end of file. */ 277d1d669bdSPawel Jakub Dawidek if (*line == '\n' || *line == '#' || *line == '\0') 278d1d669bdSPawel Jakub Dawidek continue; 279d1d669bdSPawel Jakub Dawidek 280d1d669bdSPawel Jakub Dawidek len = strlen(line); 281d1d669bdSPawel Jakub Dawidek if (line[len - 1] == '\n') { 282d1d669bdSPawel Jakub Dawidek /* Remove new line char. */ 283d1d669bdSPawel Jakub Dawidek line[len - 1] = '\0'; 284d1d669bdSPawel Jakub Dawidek } else { 285d1d669bdSPawel Jakub Dawidek if (!feof(fd)) 286d1d669bdSPawel Jakub Dawidek g_gate_xlog("Line %u too long.", lineno); 287d1d669bdSPawel Jakub Dawidek } 288d1d669bdSPawel Jakub Dawidek 289d1d669bdSPawel Jakub Dawidek line_parse(line, lineno); 290d1d669bdSPawel Jakub Dawidek objs++; 291d1d669bdSPawel Jakub Dawidek } 292d1d669bdSPawel Jakub Dawidek 293d1d669bdSPawel Jakub Dawidek fclose(fd); 294d1d669bdSPawel Jakub Dawidek 295d1d669bdSPawel Jakub Dawidek if (objs == 0) 296d1d669bdSPawel Jakub Dawidek g_gate_xlog("There are no objects to export."); 297d1d669bdSPawel Jakub Dawidek 298d1d669bdSPawel Jakub Dawidek g_gate_log(LOG_INFO, "Exporting %u object(s).", objs); 299d1d669bdSPawel Jakub Dawidek } 300d1d669bdSPawel Jakub Dawidek 3017be67fe3SPawel Jakub Dawidek static int 3027be67fe3SPawel Jakub Dawidek exports_check(struct ggd_export *ex, struct g_gate_cinit *cinit, 3037be67fe3SPawel Jakub Dawidek struct ggd_connection *conn) 304d1d669bdSPawel Jakub Dawidek { 3057be67fe3SPawel Jakub Dawidek char ipmask[32]; /* 32 == strlen("xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx")+1 */ 3067be67fe3SPawel Jakub Dawidek int error = 0, flags; 3077be67fe3SPawel Jakub Dawidek 3087be67fe3SPawel Jakub Dawidek strlcpy(ipmask, ip2str(ex->e_ip), sizeof(ipmask)); 3097be67fe3SPawel Jakub Dawidek strlcat(ipmask, "/", sizeof(ipmask)); 3107be67fe3SPawel Jakub Dawidek strlcat(ipmask, ip2str(ex->e_mask), sizeof(ipmask)); 3117be67fe3SPawel Jakub Dawidek if ((cinit->gc_flags & GGATE_FLAG_RDONLY) != 0) { 3127be67fe3SPawel Jakub Dawidek if (ex->e_flags == O_WRONLY) { 3137be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Read-only access requested, " 3147be67fe3SPawel Jakub Dawidek "but %s (%s) is exported write-only.", ex->e_path, 3157be67fe3SPawel Jakub Dawidek ipmask); 3167be67fe3SPawel Jakub Dawidek return (EPERM); 3177be67fe3SPawel Jakub Dawidek } else { 3187be67fe3SPawel Jakub Dawidek conn->c_flags |= GGATE_FLAG_RDONLY; 3197be67fe3SPawel Jakub Dawidek } 3207be67fe3SPawel Jakub Dawidek } else if ((cinit->gc_flags & GGATE_FLAG_WRONLY) != 0) { 3217be67fe3SPawel Jakub Dawidek if (ex->e_flags == O_RDONLY) { 3227be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Write-only access requested, " 3237be67fe3SPawel Jakub Dawidek "but %s (%s) is exported read-only.", ex->e_path, 3247be67fe3SPawel Jakub Dawidek ipmask); 3257be67fe3SPawel Jakub Dawidek return (EPERM); 3267be67fe3SPawel Jakub Dawidek } else { 3277be67fe3SPawel Jakub Dawidek conn->c_flags |= GGATE_FLAG_WRONLY; 3287be67fe3SPawel Jakub Dawidek } 3297be67fe3SPawel Jakub Dawidek } else { 3307be67fe3SPawel Jakub Dawidek if (ex->e_flags == O_RDONLY) { 3317be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Read-write access requested, " 3327be67fe3SPawel Jakub Dawidek "but %s (%s) is exported read-only.", ex->e_path, 3337be67fe3SPawel Jakub Dawidek ipmask); 3347be67fe3SPawel Jakub Dawidek return (EPERM); 3357be67fe3SPawel Jakub Dawidek } else if (ex->e_flags == O_WRONLY) { 3367be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Read-write access requested, " 3377be67fe3SPawel Jakub Dawidek "but %s (%s) is exported write-only.", ex->e_path, 3387be67fe3SPawel Jakub Dawidek ipmask); 3397be67fe3SPawel Jakub Dawidek return (EPERM); 3407be67fe3SPawel Jakub Dawidek } 3417be67fe3SPawel Jakub Dawidek } 3427be67fe3SPawel Jakub Dawidek if ((conn->c_flags & GGATE_FLAG_RDONLY) != 0) 3437be67fe3SPawel Jakub Dawidek flags = O_RDONLY; 3447be67fe3SPawel Jakub Dawidek else if ((conn->c_flags & GGATE_FLAG_WRONLY) != 0) 3457be67fe3SPawel Jakub Dawidek flags = O_WRONLY; 3467be67fe3SPawel Jakub Dawidek else 3477be67fe3SPawel Jakub Dawidek flags = O_RDWR; 3487be67fe3SPawel Jakub Dawidek conn->c_diskfd = open(ex->e_path, flags); 3497be67fe3SPawel Jakub Dawidek if (conn->c_diskfd == -1) { 3507be67fe3SPawel Jakub Dawidek error = errno; 3517be67fe3SPawel Jakub Dawidek g_gate_log(LOG_ERR, "Cannot open %s: %s.", ex->e_path, 3527be67fe3SPawel Jakub Dawidek strerror(error)); 3537be67fe3SPawel Jakub Dawidek return (error); 3547be67fe3SPawel Jakub Dawidek } 3557be67fe3SPawel Jakub Dawidek return (0); 3567be67fe3SPawel Jakub Dawidek } 3577be67fe3SPawel Jakub Dawidek 3587be67fe3SPawel Jakub Dawidek static struct ggd_export * 3597be67fe3SPawel Jakub Dawidek exports_find(struct sockaddr *s, struct g_gate_cinit *cinit, 3607be67fe3SPawel Jakub Dawidek struct ggd_connection *conn) 3617be67fe3SPawel Jakub Dawidek { 3627be67fe3SPawel Jakub Dawidek struct ggd_export *ex; 3637be67fe3SPawel Jakub Dawidek in_addr_t ip; 3647be67fe3SPawel Jakub Dawidek int error; 3657be67fe3SPawel Jakub Dawidek 3667be67fe3SPawel Jakub Dawidek ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); 3677be67fe3SPawel Jakub Dawidek SLIST_FOREACH(ex, &exports, e_next) { 3687be67fe3SPawel Jakub Dawidek if ((ip & ex->e_mask) != ex->e_ip) { 3697be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "exports[%s]: IP mismatch.", 3707be67fe3SPawel Jakub Dawidek ex->e_path); 3717be67fe3SPawel Jakub Dawidek continue; 3727be67fe3SPawel Jakub Dawidek } 3737be67fe3SPawel Jakub Dawidek if (strcmp(cinit->gc_path, ex->e_path) != 0) { 3747be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "exports[%s]: Path mismatch.", 3757be67fe3SPawel Jakub Dawidek ex->e_path); 3767be67fe3SPawel Jakub Dawidek continue; 3777be67fe3SPawel Jakub Dawidek } 3787be67fe3SPawel Jakub Dawidek error = exports_check(ex, cinit, conn); 3797be67fe3SPawel Jakub Dawidek if (error == 0) 3807be67fe3SPawel Jakub Dawidek return (ex); 3817be67fe3SPawel Jakub Dawidek else { 3827be67fe3SPawel Jakub Dawidek errno = error; 3837be67fe3SPawel Jakub Dawidek return (NULL); 3847be67fe3SPawel Jakub Dawidek } 3857be67fe3SPawel Jakub Dawidek } 3867be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Unauthorized connection from: %s.", 3877be67fe3SPawel Jakub Dawidek ip2str(ip)); 3887be67fe3SPawel Jakub Dawidek errno = EPERM; 3897be67fe3SPawel Jakub Dawidek return (NULL); 3907be67fe3SPawel Jakub Dawidek } 3917be67fe3SPawel Jakub Dawidek 3927be67fe3SPawel Jakub Dawidek /* 3937be67fe3SPawel Jakub Dawidek * Remove timed out connections. 3947be67fe3SPawel Jakub Dawidek */ 3957be67fe3SPawel Jakub Dawidek static void 3967be67fe3SPawel Jakub Dawidek connection_cleanups(void) 3977be67fe3SPawel Jakub Dawidek { 3987be67fe3SPawel Jakub Dawidek struct ggd_connection *conn, *tconn; 3997be67fe3SPawel Jakub Dawidek time_t now; 4007be67fe3SPawel Jakub Dawidek 4017be67fe3SPawel Jakub Dawidek time(&now); 4027be67fe3SPawel Jakub Dawidek LIST_FOREACH_SAFE(conn, &connections, c_next, tconn) { 4037be67fe3SPawel Jakub Dawidek if (now - conn->c_birthtime > 10) { 4047be67fe3SPawel Jakub Dawidek LIST_REMOVE(conn, c_next); 4057be67fe3SPawel Jakub Dawidek g_gate_log(LOG_NOTICE, 4067be67fe3SPawel Jakub Dawidek "Connection from %s [%s] removed.", 4077be67fe3SPawel Jakub Dawidek ip2str(conn->c_srcip), conn->c_path); 4087be67fe3SPawel Jakub Dawidek close(conn->c_diskfd); 4097be67fe3SPawel Jakub Dawidek close(conn->c_sendfd); 4107be67fe3SPawel Jakub Dawidek close(conn->c_recvfd); 4117be67fe3SPawel Jakub Dawidek free(conn->c_path); 4127be67fe3SPawel Jakub Dawidek free(conn); 4137be67fe3SPawel Jakub Dawidek } 4147be67fe3SPawel Jakub Dawidek } 4157be67fe3SPawel Jakub Dawidek } 4167be67fe3SPawel Jakub Dawidek 4177be67fe3SPawel Jakub Dawidek static struct ggd_connection * 4187be67fe3SPawel Jakub Dawidek connection_find(struct g_gate_cinit *cinit) 4197be67fe3SPawel Jakub Dawidek { 4207be67fe3SPawel Jakub Dawidek struct ggd_connection *conn; 4217be67fe3SPawel Jakub Dawidek 4227be67fe3SPawel Jakub Dawidek LIST_FOREACH(conn, &connections, c_next) { 4237be67fe3SPawel Jakub Dawidek if (conn->c_token == cinit->gc_token) 4247be67fe3SPawel Jakub Dawidek break; 4257be67fe3SPawel Jakub Dawidek } 4267be67fe3SPawel Jakub Dawidek return (conn); 4277be67fe3SPawel Jakub Dawidek } 4287be67fe3SPawel Jakub Dawidek 4297be67fe3SPawel Jakub Dawidek static struct ggd_connection * 4307be67fe3SPawel Jakub Dawidek connection_new(struct g_gate_cinit *cinit, struct sockaddr *s, int sfd) 4317be67fe3SPawel Jakub Dawidek { 4327be67fe3SPawel Jakub Dawidek struct ggd_connection *conn; 4337be67fe3SPawel Jakub Dawidek in_addr_t ip; 4347be67fe3SPawel Jakub Dawidek 4357be67fe3SPawel Jakub Dawidek /* 4367be67fe3SPawel Jakub Dawidek * First, look for old connections. 4377be67fe3SPawel Jakub Dawidek * We probably should do it every X seconds, but what for? 4387be67fe3SPawel Jakub Dawidek * It is only dangerous if an attacker wants to overload connections 4397be67fe3SPawel Jakub Dawidek * queue, so here is a good place to do the cleanups. 4407be67fe3SPawel Jakub Dawidek */ 4417be67fe3SPawel Jakub Dawidek connection_cleanups(); 4427be67fe3SPawel Jakub Dawidek 4437be67fe3SPawel Jakub Dawidek conn = malloc(sizeof(*conn)); 4447be67fe3SPawel Jakub Dawidek if (conn == NULL) 4457be67fe3SPawel Jakub Dawidek return (NULL); 4467be67fe3SPawel Jakub Dawidek conn->c_path = strdup(cinit->gc_path); 4477be67fe3SPawel Jakub Dawidek if (conn->c_path == NULL) { 4487be67fe3SPawel Jakub Dawidek free(conn); 4497be67fe3SPawel Jakub Dawidek return (NULL); 4507be67fe3SPawel Jakub Dawidek } 4517be67fe3SPawel Jakub Dawidek conn->c_token = cinit->gc_token; 4527be67fe3SPawel Jakub Dawidek ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); 4537be67fe3SPawel Jakub Dawidek conn->c_srcip = ip; 4547be67fe3SPawel Jakub Dawidek conn->c_sendfd = conn->c_recvfd = -1; 4557be67fe3SPawel Jakub Dawidek if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0) 4567be67fe3SPawel Jakub Dawidek conn->c_sendfd = sfd; 4577be67fe3SPawel Jakub Dawidek else 4587be67fe3SPawel Jakub Dawidek conn->c_recvfd = sfd; 4597be67fe3SPawel Jakub Dawidek conn->c_mediasize = 0; 4607be67fe3SPawel Jakub Dawidek conn->c_sectorsize = 0; 4617be67fe3SPawel Jakub Dawidek time(&conn->c_birthtime); 4627be67fe3SPawel Jakub Dawidek conn->c_flags = cinit->gc_flags; 4637be67fe3SPawel Jakub Dawidek LIST_INSERT_HEAD(&connections, conn, c_next); 4647be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Connection created [%s, %s].", ip2str(ip), 4657be67fe3SPawel Jakub Dawidek conn->c_path); 4667be67fe3SPawel Jakub Dawidek return (conn); 4677be67fe3SPawel Jakub Dawidek } 4687be67fe3SPawel Jakub Dawidek 4697be67fe3SPawel Jakub Dawidek static int 4707be67fe3SPawel Jakub Dawidek connection_add(struct ggd_connection *conn, struct g_gate_cinit *cinit, 4717be67fe3SPawel Jakub Dawidek struct sockaddr *s, int sfd) 4727be67fe3SPawel Jakub Dawidek { 473d1d669bdSPawel Jakub Dawidek in_addr_t ip; 474d1d669bdSPawel Jakub Dawidek 47586bfa454SPawel Jakub Dawidek ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); 4767be67fe3SPawel Jakub Dawidek if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0) { 4777be67fe3SPawel Jakub Dawidek if (conn->c_sendfd != -1) { 4787be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, 4797be67fe3SPawel Jakub Dawidek "Send socket already exists [%s, %s].", ip2str(ip), 4807be67fe3SPawel Jakub Dawidek conn->c_path); 4817be67fe3SPawel Jakub Dawidek return (EEXIST); 482d1d669bdSPawel Jakub Dawidek } 4837be67fe3SPawel Jakub Dawidek conn->c_sendfd = sfd; 4847be67fe3SPawel Jakub Dawidek } else { 4857be67fe3SPawel Jakub Dawidek if (conn->c_recvfd != -1) { 4867be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, 4877be67fe3SPawel Jakub Dawidek "Receive socket already exists [%s, %s].", 4887be67fe3SPawel Jakub Dawidek ip2str(ip), conn->c_path); 4897be67fe3SPawel Jakub Dawidek return (EEXIST); 4907be67fe3SPawel Jakub Dawidek } 4917be67fe3SPawel Jakub Dawidek conn->c_recvfd = sfd; 4927be67fe3SPawel Jakub Dawidek } 4937be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Connection added [%s, %s].", ip2str(ip), 4947be67fe3SPawel Jakub Dawidek conn->c_path); 4957be67fe3SPawel Jakub Dawidek return (0); 4967be67fe3SPawel Jakub Dawidek } 497d1d669bdSPawel Jakub Dawidek 4987be67fe3SPawel Jakub Dawidek /* 4997be67fe3SPawel Jakub Dawidek * Remove one socket from the given connection or the whole 5007be67fe3SPawel Jakub Dawidek * connection if sfd == -1. 5017be67fe3SPawel Jakub Dawidek */ 5027be67fe3SPawel Jakub Dawidek static void 5037be67fe3SPawel Jakub Dawidek connection_remove(struct ggd_connection *conn) 5047be67fe3SPawel Jakub Dawidek { 5057be67fe3SPawel Jakub Dawidek 5067be67fe3SPawel Jakub Dawidek LIST_REMOVE(conn, c_next); 5077be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Connection removed [%s %s].", 5087be67fe3SPawel Jakub Dawidek ip2str(conn->c_srcip), conn->c_path); 5097be67fe3SPawel Jakub Dawidek if (conn->c_sendfd != -1) 5107be67fe3SPawel Jakub Dawidek close(conn->c_sendfd); 5117be67fe3SPawel Jakub Dawidek if (conn->c_recvfd != -1) 5127be67fe3SPawel Jakub Dawidek close(conn->c_recvfd); 5137be67fe3SPawel Jakub Dawidek free(conn->c_path); 5147be67fe3SPawel Jakub Dawidek free(conn); 5157be67fe3SPawel Jakub Dawidek } 5167be67fe3SPawel Jakub Dawidek 5177be67fe3SPawel Jakub Dawidek static int 5187be67fe3SPawel Jakub Dawidek connection_ready(struct ggd_connection *conn) 5197be67fe3SPawel Jakub Dawidek { 5207be67fe3SPawel Jakub Dawidek 5217be67fe3SPawel Jakub Dawidek return (conn->c_sendfd != -1 && conn->c_recvfd != -1); 5227be67fe3SPawel Jakub Dawidek } 5237be67fe3SPawel Jakub Dawidek 5247be67fe3SPawel Jakub Dawidek static void 5257be67fe3SPawel Jakub Dawidek connection_launch(struct ggd_connection *conn) 5267be67fe3SPawel Jakub Dawidek { 5277be67fe3SPawel Jakub Dawidek pthread_t td; 5287be67fe3SPawel Jakub Dawidek int error, pid; 5297be67fe3SPawel Jakub Dawidek 5307be67fe3SPawel Jakub Dawidek pid = fork(); 5317be67fe3SPawel Jakub Dawidek if (pid > 0) 5327be67fe3SPawel Jakub Dawidek return; 5337be67fe3SPawel Jakub Dawidek else if (pid == -1) { 5347be67fe3SPawel Jakub Dawidek g_gate_log(LOG_ERR, "Cannot fork: %s.", strerror(errno)); 5357be67fe3SPawel Jakub Dawidek return; 5367be67fe3SPawel Jakub Dawidek } 5377be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Process created [%s].", conn->c_path); 5387be67fe3SPawel Jakub Dawidek 5397be67fe3SPawel Jakub Dawidek /* 5407be67fe3SPawel Jakub Dawidek * Create condition variables and mutexes for in-queue and out-queue 5417be67fe3SPawel Jakub Dawidek * synchronization. 5427be67fe3SPawel Jakub Dawidek */ 5437be67fe3SPawel Jakub Dawidek error = pthread_mutex_init(&inqueue_mtx, NULL); 5447be67fe3SPawel Jakub Dawidek if (error != 0) { 5457be67fe3SPawel Jakub Dawidek g_gate_xlog("pthread_mutex_init(inqueue_mtx): %s.", 5467be67fe3SPawel Jakub Dawidek strerror(error)); 5477be67fe3SPawel Jakub Dawidek } 5487be67fe3SPawel Jakub Dawidek error = pthread_cond_init(&inqueue_cond, NULL); 5497be67fe3SPawel Jakub Dawidek if (error != 0) { 5507be67fe3SPawel Jakub Dawidek g_gate_xlog("pthread_cond_init(inqueue_cond): %s.", 5517be67fe3SPawel Jakub Dawidek strerror(error)); 5527be67fe3SPawel Jakub Dawidek } 5537be67fe3SPawel Jakub Dawidek error = pthread_mutex_init(&outqueue_mtx, NULL); 5547be67fe3SPawel Jakub Dawidek if (error != 0) { 5557be67fe3SPawel Jakub Dawidek g_gate_xlog("pthread_mutex_init(outqueue_mtx): %s.", 5567be67fe3SPawel Jakub Dawidek strerror(error)); 5577be67fe3SPawel Jakub Dawidek } 5587be67fe3SPawel Jakub Dawidek error = pthread_cond_init(&outqueue_cond, NULL); 5597be67fe3SPawel Jakub Dawidek if (error != 0) { 5607be67fe3SPawel Jakub Dawidek g_gate_xlog("pthread_cond_init(outqueue_cond): %s.", 5617be67fe3SPawel Jakub Dawidek strerror(error)); 5627be67fe3SPawel Jakub Dawidek } 5637be67fe3SPawel Jakub Dawidek 5647be67fe3SPawel Jakub Dawidek /* 5657be67fe3SPawel Jakub Dawidek * Create threads: 5667be67fe3SPawel Jakub Dawidek * recvtd - thread for receiving I/O request 5677be67fe3SPawel Jakub Dawidek * diskio - thread for doing I/O request 5687be67fe3SPawel Jakub Dawidek * sendtd - thread for sending I/O requests back 5697be67fe3SPawel Jakub Dawidek */ 5707be67fe3SPawel Jakub Dawidek error = pthread_create(&td, NULL, send_thread, conn); 5717be67fe3SPawel Jakub Dawidek if (error != 0) { 5727be67fe3SPawel Jakub Dawidek g_gate_xlog("pthread_create(send_thread): %s.", 5737be67fe3SPawel Jakub Dawidek strerror(error)); 5747be67fe3SPawel Jakub Dawidek } 5757be67fe3SPawel Jakub Dawidek error = pthread_create(&td, NULL, recv_thread, conn); 5767be67fe3SPawel Jakub Dawidek if (error != 0) { 5777be67fe3SPawel Jakub Dawidek g_gate_xlog("pthread_create(recv_thread): %s.", 5787be67fe3SPawel Jakub Dawidek strerror(error)); 5797be67fe3SPawel Jakub Dawidek } 5807be67fe3SPawel Jakub Dawidek disk_thread(conn); 581d1d669bdSPawel Jakub Dawidek } 582d1d669bdSPawel Jakub Dawidek 583d1d669bdSPawel Jakub Dawidek static void 584d1d669bdSPawel Jakub Dawidek sendfail(int sfd, int error, const char *fmt, ...) 585d1d669bdSPawel Jakub Dawidek { 586d1d669bdSPawel Jakub Dawidek struct g_gate_sinit sinit; 587d1d669bdSPawel Jakub Dawidek va_list ap; 5887be67fe3SPawel Jakub Dawidek ssize_t data; 589d1d669bdSPawel Jakub Dawidek 590d1d669bdSPawel Jakub Dawidek sinit.gs_error = error; 591d1d669bdSPawel Jakub Dawidek g_gate_swap2n_sinit(&sinit); 5927be67fe3SPawel Jakub Dawidek data = g_gate_send(sfd, &sinit, sizeof(sinit), 0); 593d1d669bdSPawel Jakub Dawidek g_gate_swap2h_sinit(&sinit); 5947be67fe3SPawel Jakub Dawidek if (data != sizeof(sinit)) { 5957be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Cannot send initial packet: %s.", 596d1d669bdSPawel Jakub Dawidek strerror(errno)); 5977be67fe3SPawel Jakub Dawidek return; 598d1d669bdSPawel Jakub Dawidek } 599d1d669bdSPawel Jakub Dawidek if (fmt != NULL) { 600d1d669bdSPawel Jakub Dawidek va_start(ap, fmt); 6017be67fe3SPawel Jakub Dawidek g_gate_vlog(LOG_WARNING, fmt, ap); 602d1d669bdSPawel Jakub Dawidek va_end(ap); 603d1d669bdSPawel Jakub Dawidek } 604d1d669bdSPawel Jakub Dawidek } 605d1d669bdSPawel Jakub Dawidek 6067be67fe3SPawel Jakub Dawidek static void * 6077be67fe3SPawel Jakub Dawidek malloc_waitok(size_t size) 608d1d669bdSPawel Jakub Dawidek { 6097be67fe3SPawel Jakub Dawidek void *p; 6107be67fe3SPawel Jakub Dawidek 6117be67fe3SPawel Jakub Dawidek while ((p = malloc(size)) == NULL) { 6127be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Cannot allocate %zu bytes.", size); 6137be67fe3SPawel Jakub Dawidek sleep(1); 6147be67fe3SPawel Jakub Dawidek } 6157be67fe3SPawel Jakub Dawidek return (p); 6167be67fe3SPawel Jakub Dawidek } 6177be67fe3SPawel Jakub Dawidek 6187be67fe3SPawel Jakub Dawidek static void * 6197be67fe3SPawel Jakub Dawidek recv_thread(void *arg) 6207be67fe3SPawel Jakub Dawidek { 6217be67fe3SPawel Jakub Dawidek struct ggd_connection *conn; 6227be67fe3SPawel Jakub Dawidek struct ggd_request *req; 623d1d669bdSPawel Jakub Dawidek ssize_t data; 6247be67fe3SPawel Jakub Dawidek int error, fd; 625d1d669bdSPawel Jakub Dawidek 6267be67fe3SPawel Jakub Dawidek conn = arg; 6277be67fe3SPawel Jakub Dawidek g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); 6287be67fe3SPawel Jakub Dawidek fd = conn->c_recvfd; 629d1d669bdSPawel Jakub Dawidek for (;;) { 630d1d669bdSPawel Jakub Dawidek /* 6317be67fe3SPawel Jakub Dawidek * Get header packet. 632d1d669bdSPawel Jakub Dawidek */ 6337be67fe3SPawel Jakub Dawidek req = malloc_waitok(sizeof(*req)); 6347be67fe3SPawel Jakub Dawidek data = g_gate_recv(fd, &req->r_hdr, sizeof(req->r_hdr), 6357be67fe3SPawel Jakub Dawidek MSG_WAITALL); 636d1d669bdSPawel Jakub Dawidek if (data == 0) { 637d1d669bdSPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Process %u exiting.", getpid()); 638d1d669bdSPawel Jakub Dawidek exit(EXIT_SUCCESS); 639d1d669bdSPawel Jakub Dawidek } else if (data == -1) { 640d1d669bdSPawel Jakub Dawidek g_gate_xlog("Error while receiving hdr packet: %s.", 641d1d669bdSPawel Jakub Dawidek strerror(errno)); 6427be67fe3SPawel Jakub Dawidek } else if (data != sizeof(req->r_hdr)) { 643d1d669bdSPawel Jakub Dawidek g_gate_xlog("Malformed hdr packet received."); 644d1d669bdSPawel Jakub Dawidek } 645d1d669bdSPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Received hdr packet."); 6467be67fe3SPawel Jakub Dawidek g_gate_swap2h_hdr(&req->r_hdr); 6477be67fe3SPawel Jakub Dawidek 6487be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, 6497be67fe3SPawel Jakub Dawidek (intmax_t)req->r_offset, (unsigned)req->r_length); 650d1d669bdSPawel Jakub Dawidek 651d1d669bdSPawel Jakub Dawidek /* 6527be67fe3SPawel Jakub Dawidek * Allocate memory for data. 653d1d669bdSPawel Jakub Dawidek */ 6547be67fe3SPawel Jakub Dawidek req->r_data = malloc_waitok(req->r_length); 655d1d669bdSPawel Jakub Dawidek 6567be67fe3SPawel Jakub Dawidek /* 6577be67fe3SPawel Jakub Dawidek * Receive data to write for WRITE request. 6587be67fe3SPawel Jakub Dawidek */ 6597be67fe3SPawel Jakub Dawidek if (req->r_cmd == GGATE_CMD_WRITE) { 660d1d669bdSPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Waiting for %u bytes of data...", 6617be67fe3SPawel Jakub Dawidek req->r_length); 6627be67fe3SPawel Jakub Dawidek data = g_gate_recv(fd, req->r_data, req->r_length, 6637be67fe3SPawel Jakub Dawidek MSG_WAITALL); 664d1d669bdSPawel Jakub Dawidek if (data == -1) { 665d1d669bdSPawel Jakub Dawidek g_gate_xlog("Error while receiving data: %s.", 666d1d669bdSPawel Jakub Dawidek strerror(errno)); 667d1d669bdSPawel Jakub Dawidek } 668d1d669bdSPawel Jakub Dawidek } 6697be67fe3SPawel Jakub Dawidek 6707be67fe3SPawel Jakub Dawidek /* 6717be67fe3SPawel Jakub Dawidek * Put the request onto the incoming queue. 6727be67fe3SPawel Jakub Dawidek */ 6737be67fe3SPawel Jakub Dawidek error = pthread_mutex_lock(&inqueue_mtx); 6747be67fe3SPawel Jakub Dawidek assert(error == 0); 6757be67fe3SPawel Jakub Dawidek TAILQ_INSERT_TAIL(&inqueue, req, r_next); 6767be67fe3SPawel Jakub Dawidek error = pthread_cond_signal(&inqueue_cond); 6777be67fe3SPawel Jakub Dawidek assert(error == 0); 6787be67fe3SPawel Jakub Dawidek error = pthread_mutex_unlock(&inqueue_mtx); 6797be67fe3SPawel Jakub Dawidek assert(error == 0); 6807be67fe3SPawel Jakub Dawidek } 6817be67fe3SPawel Jakub Dawidek } 6827be67fe3SPawel Jakub Dawidek 6837be67fe3SPawel Jakub Dawidek static void * 6847be67fe3SPawel Jakub Dawidek disk_thread(void *arg) 6857be67fe3SPawel Jakub Dawidek { 6867be67fe3SPawel Jakub Dawidek struct ggd_connection *conn; 6877be67fe3SPawel Jakub Dawidek struct ggd_request *req; 6887be67fe3SPawel Jakub Dawidek ssize_t data; 6897be67fe3SPawel Jakub Dawidek int error, fd; 6907be67fe3SPawel Jakub Dawidek 6917be67fe3SPawel Jakub Dawidek conn = arg; 6927be67fe3SPawel Jakub Dawidek g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); 6937be67fe3SPawel Jakub Dawidek fd = conn->c_diskfd; 6947be67fe3SPawel Jakub Dawidek for (;;) { 6957be67fe3SPawel Jakub Dawidek /* 6967be67fe3SPawel Jakub Dawidek * Get a request from the incoming queue. 6977be67fe3SPawel Jakub Dawidek */ 6987be67fe3SPawel Jakub Dawidek error = pthread_mutex_lock(&inqueue_mtx); 6997be67fe3SPawel Jakub Dawidek assert(error == 0); 7007be67fe3SPawel Jakub Dawidek while ((req = TAILQ_FIRST(&inqueue)) == NULL) { 7017be67fe3SPawel Jakub Dawidek error = pthread_cond_wait(&inqueue_cond, &inqueue_mtx); 7027be67fe3SPawel Jakub Dawidek assert(error == 0); 7037be67fe3SPawel Jakub Dawidek } 7047be67fe3SPawel Jakub Dawidek TAILQ_REMOVE(&inqueue, req, r_next); 7057be67fe3SPawel Jakub Dawidek error = pthread_mutex_unlock(&inqueue_mtx); 7067be67fe3SPawel Jakub Dawidek assert(error == 0); 7077be67fe3SPawel Jakub Dawidek 7087be67fe3SPawel Jakub Dawidek /* 7097be67fe3SPawel Jakub Dawidek * Check the request. 7107be67fe3SPawel Jakub Dawidek */ 7117be67fe3SPawel Jakub Dawidek assert(req->r_cmd == GGATE_CMD_READ || req->r_cmd == GGATE_CMD_WRITE); 7127be67fe3SPawel Jakub Dawidek assert(req->r_offset + req->r_length <= (uintmax_t)conn->c_mediasize); 7137be67fe3SPawel Jakub Dawidek assert((req->r_offset % conn->c_sectorsize) == 0); 7147be67fe3SPawel Jakub Dawidek assert((req->r_length % conn->c_sectorsize) == 0); 7157be67fe3SPawel Jakub Dawidek 7167be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, 7177be67fe3SPawel Jakub Dawidek (intmax_t)req->r_offset, (unsigned)req->r_length); 7187be67fe3SPawel Jakub Dawidek 7197be67fe3SPawel Jakub Dawidek /* 7207be67fe3SPawel Jakub Dawidek * Do the request. 7217be67fe3SPawel Jakub Dawidek */ 7227be67fe3SPawel Jakub Dawidek data = 0; 7237be67fe3SPawel Jakub Dawidek switch (req->r_cmd) { 7247be67fe3SPawel Jakub Dawidek case GGATE_CMD_READ: 7257be67fe3SPawel Jakub Dawidek data = pread(fd, req->r_data, req->r_length, 7267be67fe3SPawel Jakub Dawidek req->r_offset); 7277be67fe3SPawel Jakub Dawidek break; 7287be67fe3SPawel Jakub Dawidek case GGATE_CMD_WRITE: 7297be67fe3SPawel Jakub Dawidek data = pwrite(fd, req->r_data, req->r_length, 7307be67fe3SPawel Jakub Dawidek req->r_offset); 7317be67fe3SPawel Jakub Dawidek /* Free data memory here - better sooner. */ 7327be67fe3SPawel Jakub Dawidek free(req->r_data); 7337be67fe3SPawel Jakub Dawidek req->r_data = NULL; 7347be67fe3SPawel Jakub Dawidek break; 7357be67fe3SPawel Jakub Dawidek } 7367be67fe3SPawel Jakub Dawidek if (data != (ssize_t)req->r_length) { 7377be67fe3SPawel Jakub Dawidek /* Report short reads/writes as I/O errors. */ 7387be67fe3SPawel Jakub Dawidek if (errno == 0) 7397be67fe3SPawel Jakub Dawidek errno = EIO; 7407be67fe3SPawel Jakub Dawidek g_gate_log(LOG_ERR, "Disk error: %s", strerror(errno)); 7417be67fe3SPawel Jakub Dawidek req->r_error = errno; 7427be67fe3SPawel Jakub Dawidek if (req->r_data != NULL) { 7437be67fe3SPawel Jakub Dawidek free(req->r_data); 7447be67fe3SPawel Jakub Dawidek req->r_data = NULL; 7457be67fe3SPawel Jakub Dawidek } 7467be67fe3SPawel Jakub Dawidek } 7477be67fe3SPawel Jakub Dawidek 7487be67fe3SPawel Jakub Dawidek /* 7497be67fe3SPawel Jakub Dawidek * Put the request onto the outgoing queue. 7507be67fe3SPawel Jakub Dawidek */ 7517be67fe3SPawel Jakub Dawidek error = pthread_mutex_lock(&outqueue_mtx); 7527be67fe3SPawel Jakub Dawidek assert(error == 0); 7537be67fe3SPawel Jakub Dawidek TAILQ_INSERT_TAIL(&outqueue, req, r_next); 7547be67fe3SPawel Jakub Dawidek error = pthread_cond_signal(&outqueue_cond); 7557be67fe3SPawel Jakub Dawidek assert(error == 0); 7567be67fe3SPawel Jakub Dawidek error = pthread_mutex_unlock(&outqueue_mtx); 7577be67fe3SPawel Jakub Dawidek assert(error == 0); 7587be67fe3SPawel Jakub Dawidek } 7597be67fe3SPawel Jakub Dawidek } 7607be67fe3SPawel Jakub Dawidek 7617be67fe3SPawel Jakub Dawidek static void * 7627be67fe3SPawel Jakub Dawidek send_thread(void *arg) 7637be67fe3SPawel Jakub Dawidek { 7647be67fe3SPawel Jakub Dawidek struct ggd_connection *conn; 7657be67fe3SPawel Jakub Dawidek struct ggd_request *req; 7667be67fe3SPawel Jakub Dawidek ssize_t data; 7677be67fe3SPawel Jakub Dawidek int error, fd; 7687be67fe3SPawel Jakub Dawidek 7697be67fe3SPawel Jakub Dawidek conn = arg; 7707be67fe3SPawel Jakub Dawidek g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); 7717be67fe3SPawel Jakub Dawidek fd = conn->c_sendfd; 7727be67fe3SPawel Jakub Dawidek for (;;) { 7737be67fe3SPawel Jakub Dawidek /* 7747be67fe3SPawel Jakub Dawidek * Get a request from the outgoing queue. 7757be67fe3SPawel Jakub Dawidek */ 7767be67fe3SPawel Jakub Dawidek error = pthread_mutex_lock(&outqueue_mtx); 7777be67fe3SPawel Jakub Dawidek assert(error == 0); 7787be67fe3SPawel Jakub Dawidek while ((req = TAILQ_FIRST(&outqueue)) == NULL) { 7797be67fe3SPawel Jakub Dawidek error = pthread_cond_wait(&outqueue_cond, 7807be67fe3SPawel Jakub Dawidek &outqueue_mtx); 7817be67fe3SPawel Jakub Dawidek assert(error == 0); 7827be67fe3SPawel Jakub Dawidek } 7837be67fe3SPawel Jakub Dawidek TAILQ_REMOVE(&outqueue, req, r_next); 7847be67fe3SPawel Jakub Dawidek error = pthread_mutex_unlock(&outqueue_mtx); 7857be67fe3SPawel Jakub Dawidek assert(error == 0); 7867be67fe3SPawel Jakub Dawidek 7877be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, 7887be67fe3SPawel Jakub Dawidek (intmax_t)req->r_offset, (unsigned)req->r_length); 7897be67fe3SPawel Jakub Dawidek 7907be67fe3SPawel Jakub Dawidek /* 7917be67fe3SPawel Jakub Dawidek * Send the request. 7927be67fe3SPawel Jakub Dawidek */ 7937be67fe3SPawel Jakub Dawidek g_gate_swap2n_hdr(&req->r_hdr); 7947be67fe3SPawel Jakub Dawidek if (g_gate_send(fd, &req->r_hdr, sizeof(req->r_hdr), 0) == -1) { 7957be67fe3SPawel Jakub Dawidek g_gate_xlog("Error while sending hdr packet: %s.", 796d1d669bdSPawel Jakub Dawidek strerror(errno)); 797d1d669bdSPawel Jakub Dawidek } 7987be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Sent hdr packet."); 7997be67fe3SPawel Jakub Dawidek g_gate_swap2h_hdr(&req->r_hdr); 8007be67fe3SPawel Jakub Dawidek if (req->r_data != NULL) { 8017be67fe3SPawel Jakub Dawidek data = g_gate_send(fd, req->r_data, req->r_length, 0); 8027be67fe3SPawel Jakub Dawidek if (data != (ssize_t)req->r_length) { 8037be67fe3SPawel Jakub Dawidek g_gate_xlog("Error while sending data: %s.", 8047be67fe3SPawel Jakub Dawidek strerror(errno)); 805d1d669bdSPawel Jakub Dawidek } 8067be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, 8077be67fe3SPawel Jakub Dawidek "Sent %zd bytes (offset=%ju, size=%zu).", data, 8087be67fe3SPawel Jakub Dawidek (uintmax_t)req->r_offset, (size_t)req->r_length); 8097be67fe3SPawel Jakub Dawidek free(req->r_data); 810d1d669bdSPawel Jakub Dawidek } 8117be67fe3SPawel Jakub Dawidek free(req); 8127be67fe3SPawel Jakub Dawidek } 8137be67fe3SPawel Jakub Dawidek } 8147be67fe3SPawel Jakub Dawidek 8157be67fe3SPawel Jakub Dawidek static void 8167be67fe3SPawel Jakub Dawidek log_connection(struct sockaddr *from) 8177be67fe3SPawel Jakub Dawidek { 8187be67fe3SPawel Jakub Dawidek in_addr_t ip; 8197be67fe3SPawel Jakub Dawidek 8207be67fe3SPawel Jakub Dawidek ip = htonl(((struct sockaddr_in *)(void *)from)->sin_addr.s_addr); 8217be67fe3SPawel Jakub Dawidek g_gate_log(LOG_INFO, "Connection from: %s.", ip2str(ip)); 8227be67fe3SPawel Jakub Dawidek } 8237be67fe3SPawel Jakub Dawidek 8247be67fe3SPawel Jakub Dawidek static int 8257be67fe3SPawel Jakub Dawidek handshake(struct sockaddr *from, int sfd) 8267be67fe3SPawel Jakub Dawidek { 8277be67fe3SPawel Jakub Dawidek struct g_gate_version ver; 8287be67fe3SPawel Jakub Dawidek struct g_gate_cinit cinit; 8297be67fe3SPawel Jakub Dawidek struct g_gate_sinit sinit; 8307be67fe3SPawel Jakub Dawidek struct ggd_connection *conn; 8317be67fe3SPawel Jakub Dawidek struct ggd_export *ex; 8327be67fe3SPawel Jakub Dawidek ssize_t data; 8337be67fe3SPawel Jakub Dawidek 8347be67fe3SPawel Jakub Dawidek log_connection(from); 8357be67fe3SPawel Jakub Dawidek /* 8367be67fe3SPawel Jakub Dawidek * Phase 1: Version verification. 8377be67fe3SPawel Jakub Dawidek */ 8387be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Receiving version packet."); 8397be67fe3SPawel Jakub Dawidek data = g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL); 8407be67fe3SPawel Jakub Dawidek g_gate_swap2h_version(&ver); 8417be67fe3SPawel Jakub Dawidek if (data != sizeof(ver)) { 8427be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Malformed version packet."); 8437be67fe3SPawel Jakub Dawidek return (0); 8447be67fe3SPawel Jakub Dawidek } 8457be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Version packet received."); 8467be67fe3SPawel Jakub Dawidek if (memcmp(ver.gv_magic, GGATE_MAGIC, strlen(GGATE_MAGIC)) != 0) { 8477be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Invalid magic field."); 8487be67fe3SPawel Jakub Dawidek return (0); 8497be67fe3SPawel Jakub Dawidek } 8507be67fe3SPawel Jakub Dawidek if (ver.gv_version != GGATE_VERSION) { 8517be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Version %u is not supported.", 8527be67fe3SPawel Jakub Dawidek ver.gv_version); 8537be67fe3SPawel Jakub Dawidek return (0); 8547be67fe3SPawel Jakub Dawidek } 8557be67fe3SPawel Jakub Dawidek ver.gv_error = 0; 8567be67fe3SPawel Jakub Dawidek g_gate_swap2n_version(&ver); 8577be67fe3SPawel Jakub Dawidek data = g_gate_send(sfd, &ver, sizeof(ver), 0); 8587be67fe3SPawel Jakub Dawidek g_gate_swap2h_version(&ver); 8597be67fe3SPawel Jakub Dawidek if (data == -1) { 8607be67fe3SPawel Jakub Dawidek sendfail(sfd, errno, "Error while sending version packet: %s.", 8617be67fe3SPawel Jakub Dawidek strerror(errno)); 8627be67fe3SPawel Jakub Dawidek return (0); 8637be67fe3SPawel Jakub Dawidek } 8647be67fe3SPawel Jakub Dawidek 8657be67fe3SPawel Jakub Dawidek /* 8667be67fe3SPawel Jakub Dawidek * Phase 2: Request verification. 8677be67fe3SPawel Jakub Dawidek */ 8687be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Receiving initial packet."); 8697be67fe3SPawel Jakub Dawidek data = g_gate_recv(sfd, &cinit, sizeof(cinit), MSG_WAITALL); 8707be67fe3SPawel Jakub Dawidek g_gate_swap2h_cinit(&cinit); 8717be67fe3SPawel Jakub Dawidek if (data != sizeof(cinit)) { 8727be67fe3SPawel Jakub Dawidek g_gate_log(LOG_WARNING, "Malformed initial packet."); 8737be67fe3SPawel Jakub Dawidek return (0); 8747be67fe3SPawel Jakub Dawidek } 8757be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Initial packet received."); 8767be67fe3SPawel Jakub Dawidek conn = connection_find(&cinit); 8777be67fe3SPawel Jakub Dawidek if (conn != NULL) { 8787be67fe3SPawel Jakub Dawidek /* 8797be67fe3SPawel Jakub Dawidek * Connection should already exists. 8807be67fe3SPawel Jakub Dawidek */ 8817be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Found existing connection (token=%lu).", 8827be67fe3SPawel Jakub Dawidek (unsigned long)conn->c_token); 8837be67fe3SPawel Jakub Dawidek if (connection_add(conn, &cinit, from, sfd) == -1) { 8847be67fe3SPawel Jakub Dawidek connection_remove(conn); 8857be67fe3SPawel Jakub Dawidek return (0); 8867be67fe3SPawel Jakub Dawidek } 8877be67fe3SPawel Jakub Dawidek } else { 8887be67fe3SPawel Jakub Dawidek /* 8897be67fe3SPawel Jakub Dawidek * New connection, allocate space. 8907be67fe3SPawel Jakub Dawidek */ 8917be67fe3SPawel Jakub Dawidek conn = connection_new(&cinit, from, sfd); 8927be67fe3SPawel Jakub Dawidek if (conn == NULL) { 8937be67fe3SPawel Jakub Dawidek sendfail(sfd, ENOMEM, 8947be67fe3SPawel Jakub Dawidek "Cannot allocate new connection."); 8957be67fe3SPawel Jakub Dawidek return (0); 8967be67fe3SPawel Jakub Dawidek } 8977be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "New connection created (token=%lu).", 8987be67fe3SPawel Jakub Dawidek (unsigned long)conn->c_token); 8997be67fe3SPawel Jakub Dawidek } 9007be67fe3SPawel Jakub Dawidek 9017be67fe3SPawel Jakub Dawidek ex = exports_find(from, &cinit, conn); 9027be67fe3SPawel Jakub Dawidek if (ex == NULL) { 9037be67fe3SPawel Jakub Dawidek connection_remove(conn); 9047be67fe3SPawel Jakub Dawidek sendfail(sfd, errno, NULL); 9057be67fe3SPawel Jakub Dawidek return (0); 9067be67fe3SPawel Jakub Dawidek } 9077be67fe3SPawel Jakub Dawidek if (conn->c_mediasize == 0) { 9087be67fe3SPawel Jakub Dawidek conn->c_mediasize = g_gate_mediasize(conn->c_diskfd); 9097be67fe3SPawel Jakub Dawidek conn->c_sectorsize = g_gate_sectorsize(conn->c_diskfd); 9107be67fe3SPawel Jakub Dawidek } 9117be67fe3SPawel Jakub Dawidek sinit.gs_mediasize = conn->c_mediasize; 9127be67fe3SPawel Jakub Dawidek sinit.gs_sectorsize = conn->c_sectorsize; 9137be67fe3SPawel Jakub Dawidek sinit.gs_error = 0; 9147be67fe3SPawel Jakub Dawidek 9157be67fe3SPawel Jakub Dawidek g_gate_log(LOG_DEBUG, "Sending initial packet."); 9167be67fe3SPawel Jakub Dawidek 9177be67fe3SPawel Jakub Dawidek g_gate_swap2n_sinit(&sinit); 9187be67fe3SPawel Jakub Dawidek data = g_gate_send(sfd, &sinit, sizeof(sinit), 0); 9197be67fe3SPawel Jakub Dawidek g_gate_swap2h_sinit(&sinit); 9207be67fe3SPawel Jakub Dawidek if (data == -1) { 9217be67fe3SPawel Jakub Dawidek sendfail(sfd, errno, "Error while sending initial packet: %s.", 9227be67fe3SPawel Jakub Dawidek strerror(errno)); 9237be67fe3SPawel Jakub Dawidek return (0); 9247be67fe3SPawel Jakub Dawidek } 9257be67fe3SPawel Jakub Dawidek 9267be67fe3SPawel Jakub Dawidek if (connection_ready(conn)) { 9277be67fe3SPawel Jakub Dawidek connection_launch(conn); 9287be67fe3SPawel Jakub Dawidek connection_remove(conn); 9297be67fe3SPawel Jakub Dawidek } 9307be67fe3SPawel Jakub Dawidek return (1); 931d1d669bdSPawel Jakub Dawidek } 932d1d669bdSPawel Jakub Dawidek 933d1d669bdSPawel Jakub Dawidek static void 934d1d669bdSPawel Jakub Dawidek huphandler(int sig __unused) 935d1d669bdSPawel Jakub Dawidek { 936d1d669bdSPawel Jakub Dawidek 937d1d669bdSPawel Jakub Dawidek got_sighup = 1; 938d1d669bdSPawel Jakub Dawidek } 939d1d669bdSPawel Jakub Dawidek 940d1d669bdSPawel Jakub Dawidek int 941d1d669bdSPawel Jakub Dawidek main(int argc, char *argv[]) 942d1d669bdSPawel Jakub Dawidek { 943d1d669bdSPawel Jakub Dawidek struct sockaddr_in serv; 944d1d669bdSPawel Jakub Dawidek struct sockaddr from; 945d1d669bdSPawel Jakub Dawidek socklen_t fromlen; 9467be67fe3SPawel Jakub Dawidek int sfd, tmpsfd; 9477be67fe3SPawel Jakub Dawidek unsigned port; 948d1d669bdSPawel Jakub Dawidek 949d1d669bdSPawel Jakub Dawidek bindaddr = htonl(INADDR_ANY); 950d1d669bdSPawel Jakub Dawidek port = G_GATE_PORT; 951d1d669bdSPawel Jakub Dawidek for (;;) { 952d1d669bdSPawel Jakub Dawidek int ch; 953d1d669bdSPawel Jakub Dawidek 954d1d669bdSPawel Jakub Dawidek ch = getopt(argc, argv, "a:hnp:R:S:v"); 955d1d669bdSPawel Jakub Dawidek if (ch == -1) 956d1d669bdSPawel Jakub Dawidek break; 957d1d669bdSPawel Jakub Dawidek switch (ch) { 958d1d669bdSPawel Jakub Dawidek case 'a': 959d1d669bdSPawel Jakub Dawidek bindaddr = g_gate_str2ip(optarg); 960d1d669bdSPawel Jakub Dawidek if (bindaddr == INADDR_NONE) { 961d1d669bdSPawel Jakub Dawidek errx(EXIT_FAILURE, 962d1d669bdSPawel Jakub Dawidek "Invalid IP/host name to bind to."); 963d1d669bdSPawel Jakub Dawidek } 964d1d669bdSPawel Jakub Dawidek break; 965d1d669bdSPawel Jakub Dawidek case 'n': 966d1d669bdSPawel Jakub Dawidek nagle = 0; 967d1d669bdSPawel Jakub Dawidek break; 968d1d669bdSPawel Jakub Dawidek case 'p': 969d1d669bdSPawel Jakub Dawidek errno = 0; 970d1d669bdSPawel Jakub Dawidek port = strtoul(optarg, NULL, 10); 971d1d669bdSPawel Jakub Dawidek if (port == 0 && errno != 0) 972d1d669bdSPawel Jakub Dawidek errx(EXIT_FAILURE, "Invalid port."); 973d1d669bdSPawel Jakub Dawidek break; 974d1d669bdSPawel Jakub Dawidek case 'R': 975d1d669bdSPawel Jakub Dawidek errno = 0; 976d1d669bdSPawel Jakub Dawidek rcvbuf = strtoul(optarg, NULL, 10); 977d1d669bdSPawel Jakub Dawidek if (rcvbuf == 0 && errno != 0) 978d1d669bdSPawel Jakub Dawidek errx(EXIT_FAILURE, "Invalid rcvbuf."); 979d1d669bdSPawel Jakub Dawidek break; 980d1d669bdSPawel Jakub Dawidek case 'S': 981d1d669bdSPawel Jakub Dawidek errno = 0; 982d1d669bdSPawel Jakub Dawidek sndbuf = strtoul(optarg, NULL, 10); 983d1d669bdSPawel Jakub Dawidek if (sndbuf == 0 && errno != 0) 984d1d669bdSPawel Jakub Dawidek errx(EXIT_FAILURE, "Invalid sndbuf."); 985d1d669bdSPawel Jakub Dawidek break; 986d1d669bdSPawel Jakub Dawidek case 'v': 987d1d669bdSPawel Jakub Dawidek g_gate_verbose++; 988d1d669bdSPawel Jakub Dawidek break; 989d1d669bdSPawel Jakub Dawidek case 'h': 990d1d669bdSPawel Jakub Dawidek default: 991d1d669bdSPawel Jakub Dawidek usage(); 992d1d669bdSPawel Jakub Dawidek } 993d1d669bdSPawel Jakub Dawidek } 994d1d669bdSPawel Jakub Dawidek argc -= optind; 995d1d669bdSPawel Jakub Dawidek argv += optind; 996d1d669bdSPawel Jakub Dawidek 997d1d669bdSPawel Jakub Dawidek if (argv[0] != NULL) 9987be67fe3SPawel Jakub Dawidek exports_file = argv[0]; 999d1d669bdSPawel Jakub Dawidek exports_get(); 1000d1d669bdSPawel Jakub Dawidek 1001d1d669bdSPawel Jakub Dawidek if (!g_gate_verbose) { 1002d1d669bdSPawel Jakub Dawidek /* Run in daemon mode. */ 1003122abe03SPawel Jakub Dawidek if (daemon(0, 0) == -1) 10047be67fe3SPawel Jakub Dawidek g_gate_xlog("Cannot daemonize: %s", strerror(errno)); 1005d1d669bdSPawel Jakub Dawidek } 1006d1d669bdSPawel Jakub Dawidek 1007d1d669bdSPawel Jakub Dawidek signal(SIGCHLD, SIG_IGN); 1008d1d669bdSPawel Jakub Dawidek 1009d1d669bdSPawel Jakub Dawidek sfd = socket(AF_INET, SOCK_STREAM, 0); 1010122abe03SPawel Jakub Dawidek if (sfd == -1) 10117be67fe3SPawel Jakub Dawidek g_gate_xlog("Cannot open stream socket: %s.", strerror(errno)); 1012d1d669bdSPawel Jakub Dawidek bzero(&serv, sizeof(serv)); 1013d1d669bdSPawel Jakub Dawidek serv.sin_family = AF_INET; 1014d1d669bdSPawel Jakub Dawidek serv.sin_addr.s_addr = bindaddr; 1015d1d669bdSPawel Jakub Dawidek serv.sin_port = htons(port); 10167be67fe3SPawel Jakub Dawidek 10177be67fe3SPawel Jakub Dawidek g_gate_socket_settings(sfd); 10187be67fe3SPawel Jakub Dawidek 1019122abe03SPawel Jakub Dawidek if (bind(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) 1020d1d669bdSPawel Jakub Dawidek g_gate_xlog("bind(): %s.", strerror(errno)); 1021122abe03SPawel Jakub Dawidek if (listen(sfd, 5) == -1) 1022d1d669bdSPawel Jakub Dawidek g_gate_xlog("listen(): %s.", strerror(errno)); 1023d1d669bdSPawel Jakub Dawidek 1024d1d669bdSPawel Jakub Dawidek g_gate_log(LOG_INFO, "Listen on port: %d.", port); 1025d1d669bdSPawel Jakub Dawidek 1026d1d669bdSPawel Jakub Dawidek signal(SIGHUP, huphandler); 1027d1d669bdSPawel Jakub Dawidek 1028d1d669bdSPawel Jakub Dawidek for (;;) { 1029d1d669bdSPawel Jakub Dawidek fromlen = sizeof(from); 1030d1d669bdSPawel Jakub Dawidek tmpsfd = accept(sfd, &from, &fromlen); 1031122abe03SPawel Jakub Dawidek if (tmpsfd == -1) 1032d1d669bdSPawel Jakub Dawidek g_gate_xlog("accept(): %s.", strerror(errno)); 1033d1d669bdSPawel Jakub Dawidek 1034d1d669bdSPawel Jakub Dawidek if (got_sighup) { 1035d1d669bdSPawel Jakub Dawidek got_sighup = 0; 1036d1d669bdSPawel Jakub Dawidek exports_get(); 1037d1d669bdSPawel Jakub Dawidek } 1038d1d669bdSPawel Jakub Dawidek 10397be67fe3SPawel Jakub Dawidek if (!handshake(&from, tmpsfd)) 1040d1d669bdSPawel Jakub Dawidek close(tmpsfd); 1041d1d669bdSPawel Jakub Dawidek } 1042d1d669bdSPawel Jakub Dawidek close(sfd); 1043d1d669bdSPawel Jakub Dawidek exit(EXIT_SUCCESS); 1044d1d669bdSPawel Jakub Dawidek } 1045