1128766Spjd/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4128766Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5128766Spjd * All rights reserved. 6128766Spjd * 7128766Spjd * Redistribution and use in source and binary forms, with or without 8128766Spjd * modification, are permitted provided that the following conditions 9128766Spjd * are met: 10128766Spjd * 1. Redistributions of source code must retain the above copyright 11128766Spjd * notice, this list of conditions and the following disclaimer. 12128766Spjd * 2. Redistributions in binary form must reproduce the above copyright 13128766Spjd * notice, this list of conditions and the following disclaimer in the 14128766Spjd * documentation and/or other materials provided with the distribution. 15204075Spjd * 16128766Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17128766Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18128766Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19128766Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20128766Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21128766Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22128766Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23128766Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24128766Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25128766Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26128766Spjd * SUCH DAMAGE. 27128766Spjd * 28128766Spjd * $FreeBSD: stable/11/sbin/ggate/ggated/ggated.c 330449 2018-03-05 07:26:05Z eadler $ 29128766Spjd */ 30128766Spjd 31128766Spjd#include <sys/param.h> 32294973Sngie#include <sys/bio.h> 33294973Sngie#include <sys/disk.h> 34294973Sngie#include <sys/endian.h> 35294973Sngie#include <sys/ioctl.h> 36128766Spjd#include <sys/queue.h> 37128766Spjd#include <sys/socket.h> 38128766Spjd#include <sys/stat.h> 39128912Sbde#include <sys/time.h> 40294973Sngie#include <arpa/inet.h> 41128766Spjd#include <netinet/in.h> 42128766Spjd#include <netinet/tcp.h> 43147844Spjd#include <assert.h> 44128766Spjd#include <err.h> 45128766Spjd#include <errno.h> 46294973Sngie#include <fcntl.h> 47294973Sngie#include <libgen.h> 48294973Sngie#include <libutil.h> 49294973Sngie#include <paths.h> 50294973Sngie#include <pthread.h> 51294973Sngie#include <signal.h> 52294973Sngie#include <stdarg.h> 53294973Sngie#include <stdio.h> 54294973Sngie#include <stdlib.h> 55294973Sngie#include <stdint.h> 56128766Spjd#include <string.h> 57128766Spjd#include <syslog.h> 58294973Sngie#include <unistd.h> 59128766Spjd 60128766Spjd#include "ggate.h" 61128766Spjd 62128766Spjd 63147844Spjd#define GGATED_EXPORT_FILE "/etc/gg.exports" 64128766Spjd 65147844Spjdstruct ggd_connection { 66147844Spjd off_t c_mediasize; 67165327Spjd unsigned c_sectorsize; 68147844Spjd unsigned c_flags; /* flags (RO/RW) */ 69147844Spjd int c_diskfd; 70147844Spjd int c_sendfd; 71147844Spjd int c_recvfd; 72147844Spjd time_t c_birthtime; 73147844Spjd char *c_path; 74147844Spjd uint64_t c_token; 75147844Spjd in_addr_t c_srcip; 76147844Spjd LIST_ENTRY(ggd_connection) c_next; 77147844Spjd}; 78128766Spjd 79147844Spjdstruct ggd_request { 80147844Spjd struct g_gate_hdr r_hdr; 81147844Spjd char *r_data; 82147844Spjd TAILQ_ENTRY(ggd_request) r_next; 83147844Spjd}; 84147844Spjd#define r_cmd r_hdr.gh_cmd 85147844Spjd#define r_offset r_hdr.gh_offset 86147844Spjd#define r_length r_hdr.gh_length 87147844Spjd#define r_error r_hdr.gh_error 88147844Spjd 89147844Spjdstruct ggd_export { 90128766Spjd char *e_path; /* path to device/file */ 91128766Spjd in_addr_t e_ip; /* remote IP address */ 92128766Spjd in_addr_t e_mask; /* IP mask */ 93128766Spjd unsigned e_flags; /* flags (RO/RW) */ 94147844Spjd SLIST_ENTRY(ggd_export) e_next; 95128766Spjd}; 96128766Spjd 97147844Spjdstatic const char *exports_file = GGATED_EXPORT_FILE; 98147844Spjdstatic int got_sighup = 0; 99241720Sedstatic in_addr_t bindaddr; 100147844Spjd 101147844Spjdstatic TAILQ_HEAD(, ggd_request) inqueue = TAILQ_HEAD_INITIALIZER(inqueue); 102147844Spjdstatic TAILQ_HEAD(, ggd_request) outqueue = TAILQ_HEAD_INITIALIZER(outqueue); 103241720Sedstatic pthread_mutex_t inqueue_mtx, outqueue_mtx; 104241720Sedstatic pthread_cond_t inqueue_cond, outqueue_cond; 105147844Spjd 106201145Santoinestatic SLIST_HEAD(, ggd_export) exports = SLIST_HEAD_INITIALIZER(exports); 107201145Santoinestatic LIST_HEAD(, ggd_connection) connections = LIST_HEAD_INITIALIZER(connections); 108147844Spjd 109147844Spjdstatic void *recv_thread(void *arg); 110147844Spjdstatic void *disk_thread(void *arg); 111147844Spjdstatic void *send_thread(void *arg); 112147844Spjd 113128766Spjdstatic void 114128766Spjdusage(void) 115128766Spjd{ 116128766Spjd 117294973Sngie fprintf(stderr, "usage: %s [-nv] [-a address] [-F pidfile] [-p port] " 118294973Sngie "[-R rcvbuf] [-S sndbuf] [exports file]\n", getprogname()); 119128766Spjd exit(EXIT_FAILURE); 120128766Spjd} 121128766Spjd 122128766Spjdstatic char * 123128766Spjdip2str(in_addr_t ip) 124128766Spjd{ 125128766Spjd static char sip[16]; 126128766Spjd 127128766Spjd snprintf(sip, sizeof(sip), "%u.%u.%u.%u", 128128766Spjd ((ip >> 24) & 0xff), 129128766Spjd ((ip >> 16) & 0xff), 130128766Spjd ((ip >> 8) & 0xff), 131128766Spjd (ip & 0xff)); 132128766Spjd return (sip); 133128766Spjd} 134128766Spjd 135128766Spjdstatic in_addr_t 136128766Spjdcountmask(unsigned m) 137128766Spjd{ 138128766Spjd in_addr_t mask; 139128766Spjd 140128766Spjd if (m == 0) { 141128766Spjd mask = 0x0; 142128766Spjd } else { 143128766Spjd mask = 1 << (32 - m); 144128766Spjd mask--; 145128766Spjd mask = ~mask; 146128766Spjd } 147128766Spjd return (mask); 148128766Spjd} 149128766Spjd 150128766Spjdstatic void 151128766Spjdline_parse(char *line, unsigned lineno) 152128766Spjd{ 153147844Spjd struct ggd_export *ex; 154128766Spjd char *word, *path, *sflags; 155128766Spjd unsigned flags, i, vmask; 156128766Spjd in_addr_t ip, mask; 157128766Spjd 158128766Spjd ip = mask = flags = vmask = 0; 159128766Spjd path = NULL; 160128766Spjd sflags = NULL; 161128766Spjd 162128766Spjd for (i = 0, word = strtok(line, " \t"); word != NULL; 163128766Spjd i++, word = strtok(NULL, " \t")) { 164128766Spjd switch (i) { 165128766Spjd case 0: /* IP address or host name */ 166128766Spjd ip = g_gate_str2ip(strsep(&word, "/")); 167128766Spjd if (ip == INADDR_NONE) { 168128766Spjd g_gate_xlog("Invalid IP/host name at line %u.", 169128766Spjd lineno); 170128766Spjd } 171128766Spjd ip = ntohl(ip); 172128766Spjd if (word == NULL) 173128766Spjd vmask = 32; 174128766Spjd else { 175128766Spjd errno = 0; 176128766Spjd vmask = strtoul(word, NULL, 10); 177128766Spjd if (vmask == 0 && errno != 0) { 178128766Spjd g_gate_xlog("Invalid IP mask value at " 179128766Spjd "line %u.", lineno); 180128766Spjd } 181128766Spjd if ((unsigned)vmask > 32) { 182128766Spjd g_gate_xlog("Invalid IP mask value at line %u.", 183128766Spjd lineno); 184128766Spjd } 185128766Spjd } 186128766Spjd mask = countmask(vmask); 187128766Spjd break; 188128766Spjd case 1: /* flags */ 189128766Spjd if (strcasecmp("rd", word) == 0 || 190128766Spjd strcasecmp("ro", word) == 0) { 191128766Spjd flags = O_RDONLY; 192128766Spjd } else if (strcasecmp("wo", word) == 0) { 193128766Spjd flags = O_WRONLY; 194128766Spjd } else if (strcasecmp("rw", word) == 0) { 195128766Spjd flags = O_RDWR; 196128766Spjd } else { 197128766Spjd g_gate_xlog("Invalid value in flags field at " 198128766Spjd "line %u.", lineno); 199128766Spjd } 200128766Spjd sflags = word; 201128766Spjd break; 202128766Spjd case 2: /* path */ 203128766Spjd if (strlen(word) >= MAXPATHLEN) { 204128766Spjd g_gate_xlog("Path too long at line %u. ", 205128766Spjd lineno); 206128766Spjd } 207128766Spjd path = word; 208128766Spjd break; 209128766Spjd default: 210128766Spjd g_gate_xlog("Too many arguments at line %u. ", lineno); 211128766Spjd } 212128766Spjd } 213128766Spjd if (i != 3) 214128766Spjd g_gate_xlog("Too few arguments at line %u.", lineno); 215128766Spjd 216128766Spjd ex = malloc(sizeof(*ex)); 217128766Spjd if (ex == NULL) 218179900Sgonzo g_gate_xlog("Not enough memory."); 219128766Spjd ex->e_path = strdup(path); 220128766Spjd if (ex->e_path == NULL) 221179900Sgonzo g_gate_xlog("Not enough memory."); 222128766Spjd 223128766Spjd /* Made 'and' here. */ 224128766Spjd ex->e_ip = (ip & mask); 225128766Spjd ex->e_mask = mask; 226128766Spjd ex->e_flags = flags; 227128766Spjd 228147844Spjd SLIST_INSERT_HEAD(&exports, ex, e_next); 229128766Spjd 230128766Spjd g_gate_log(LOG_DEBUG, "Added %s/%u %s %s to exports list.", 231128766Spjd ip2str(ex->e_ip), vmask, path, sflags); 232128766Spjd} 233128766Spjd 234128766Spjdstatic void 235128766Spjdexports_clear(void) 236128766Spjd{ 237147844Spjd struct ggd_export *ex; 238128766Spjd 239147844Spjd while (!SLIST_EMPTY(&exports)) { 240147844Spjd ex = SLIST_FIRST(&exports); 241147844Spjd SLIST_REMOVE_HEAD(&exports, e_next); 242128766Spjd free(ex); 243128766Spjd } 244128766Spjd} 245128766Spjd 246128766Spjd#define EXPORTS_LINE_SIZE 2048 247128766Spjdstatic void 248128766Spjdexports_get(void) 249128766Spjd{ 250128766Spjd char buf[EXPORTS_LINE_SIZE], *line; 251128766Spjd unsigned lineno = 0, objs = 0, len; 252128766Spjd FILE *fd; 253128766Spjd 254128766Spjd exports_clear(); 255128766Spjd 256147844Spjd fd = fopen(exports_file, "r"); 257128766Spjd if (fd == NULL) { 258147844Spjd g_gate_xlog("Cannot open exports file (%s): %s.", exports_file, 259128766Spjd strerror(errno)); 260128766Spjd } 261128766Spjd 262147844Spjd g_gate_log(LOG_INFO, "Reading exports file (%s).", exports_file); 263128766Spjd 264128766Spjd for (;;) { 265128766Spjd if (fgets(buf, sizeof(buf), fd) == NULL) { 266128766Spjd if (feof(fd)) 267128766Spjd break; 268128766Spjd 269128766Spjd g_gate_xlog("Error while reading exports file: %s.", 270128766Spjd strerror(errno)); 271128766Spjd } 272128766Spjd 273128766Spjd /* Increase line count. */ 274128766Spjd lineno++; 275128766Spjd 276128766Spjd /* Skip spaces and tabs. */ 277128766Spjd for (line = buf; *line == ' ' || *line == '\t'; ++line) 278128766Spjd ; 279128766Spjd 280128766Spjd /* Empty line, comment or empty line at the end of file. */ 281128766Spjd if (*line == '\n' || *line == '#' || *line == '\0') 282128766Spjd continue; 283128766Spjd 284128766Spjd len = strlen(line); 285128766Spjd if (line[len - 1] == '\n') { 286128766Spjd /* Remove new line char. */ 287128766Spjd line[len - 1] = '\0'; 288128766Spjd } else { 289128766Spjd if (!feof(fd)) 290128766Spjd g_gate_xlog("Line %u too long.", lineno); 291128766Spjd } 292128766Spjd 293128766Spjd line_parse(line, lineno); 294128766Spjd objs++; 295128766Spjd } 296128766Spjd 297128766Spjd fclose(fd); 298128766Spjd 299128766Spjd if (objs == 0) 300128766Spjd g_gate_xlog("There are no objects to export."); 301128766Spjd 302128766Spjd g_gate_log(LOG_INFO, "Exporting %u object(s).", objs); 303128766Spjd} 304128766Spjd 305147844Spjdstatic int 306147844Spjdexports_check(struct ggd_export *ex, struct g_gate_cinit *cinit, 307147844Spjd struct ggd_connection *conn) 308128766Spjd{ 309147844Spjd char ipmask[32]; /* 32 == strlen("xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx")+1 */ 310147844Spjd int error = 0, flags; 311147844Spjd 312147844Spjd strlcpy(ipmask, ip2str(ex->e_ip), sizeof(ipmask)); 313147844Spjd strlcat(ipmask, "/", sizeof(ipmask)); 314147844Spjd strlcat(ipmask, ip2str(ex->e_mask), sizeof(ipmask)); 315147844Spjd if ((cinit->gc_flags & GGATE_FLAG_RDONLY) != 0) { 316147844Spjd if (ex->e_flags == O_WRONLY) { 317147844Spjd g_gate_log(LOG_WARNING, "Read-only access requested, " 318147844Spjd "but %s (%s) is exported write-only.", ex->e_path, 319147844Spjd ipmask); 320147844Spjd return (EPERM); 321147844Spjd } else { 322147844Spjd conn->c_flags |= GGATE_FLAG_RDONLY; 323147844Spjd } 324147844Spjd } else if ((cinit->gc_flags & GGATE_FLAG_WRONLY) != 0) { 325147844Spjd if (ex->e_flags == O_RDONLY) { 326147844Spjd g_gate_log(LOG_WARNING, "Write-only access requested, " 327147844Spjd "but %s (%s) is exported read-only.", ex->e_path, 328147844Spjd ipmask); 329147844Spjd return (EPERM); 330147844Spjd } else { 331147844Spjd conn->c_flags |= GGATE_FLAG_WRONLY; 332147844Spjd } 333147844Spjd } else { 334147844Spjd if (ex->e_flags == O_RDONLY) { 335147844Spjd g_gate_log(LOG_WARNING, "Read-write access requested, " 336147844Spjd "but %s (%s) is exported read-only.", ex->e_path, 337147844Spjd ipmask); 338147844Spjd return (EPERM); 339147844Spjd } else if (ex->e_flags == O_WRONLY) { 340147844Spjd g_gate_log(LOG_WARNING, "Read-write access requested, " 341147844Spjd "but %s (%s) is exported write-only.", ex->e_path, 342147844Spjd ipmask); 343147844Spjd return (EPERM); 344147844Spjd } 345147844Spjd } 346147844Spjd if ((conn->c_flags & GGATE_FLAG_RDONLY) != 0) 347147844Spjd flags = O_RDONLY; 348147844Spjd else if ((conn->c_flags & GGATE_FLAG_WRONLY) != 0) 349147844Spjd flags = O_WRONLY; 350147844Spjd else 351147844Spjd flags = O_RDWR; 352147844Spjd conn->c_diskfd = open(ex->e_path, flags); 353147844Spjd if (conn->c_diskfd == -1) { 354147844Spjd error = errno; 355147844Spjd g_gate_log(LOG_ERR, "Cannot open %s: %s.", ex->e_path, 356147844Spjd strerror(error)); 357147844Spjd return (error); 358147844Spjd } 359147844Spjd return (0); 360147844Spjd} 361147844Spjd 362147844Spjdstatic struct ggd_export * 363147844Spjdexports_find(struct sockaddr *s, struct g_gate_cinit *cinit, 364147844Spjd struct ggd_connection *conn) 365147844Spjd{ 366147844Spjd struct ggd_export *ex; 367128766Spjd in_addr_t ip; 368147844Spjd int error; 369128766Spjd 370128836Spjd ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); 371147844Spjd SLIST_FOREACH(ex, &exports, e_next) { 372147844Spjd if ((ip & ex->e_mask) != ex->e_ip) { 373147844Spjd g_gate_log(LOG_DEBUG, "exports[%s]: IP mismatch.", 374147844Spjd ex->e_path); 375128766Spjd continue; 376147844Spjd } 377147844Spjd if (strcmp(cinit->gc_path, ex->e_path) != 0) { 378147844Spjd g_gate_log(LOG_DEBUG, "exports[%s]: Path mismatch.", 379147844Spjd ex->e_path); 380128766Spjd continue; 381147844Spjd } 382147844Spjd error = exports_check(ex, cinit, conn); 383147844Spjd if (error == 0) 384147844Spjd return (ex); 385147844Spjd else { 386147844Spjd errno = error; 387147844Spjd return (NULL); 388147844Spjd } 389128766Spjd } 390147844Spjd g_gate_log(LOG_WARNING, "Unauthorized connection from: %s.", 391147844Spjd ip2str(ip)); 392147844Spjd errno = EPERM; 393128766Spjd return (NULL); 394128766Spjd} 395128766Spjd 396147844Spjd/* 397147844Spjd * Remove timed out connections. 398147844Spjd */ 399128766Spjdstatic void 400147844Spjdconnection_cleanups(void) 401128766Spjd{ 402147844Spjd struct ggd_connection *conn, *tconn; 403147844Spjd time_t now; 404128766Spjd 405147844Spjd time(&now); 406147844Spjd LIST_FOREACH_SAFE(conn, &connections, c_next, tconn) { 407147844Spjd if (now - conn->c_birthtime > 10) { 408147844Spjd LIST_REMOVE(conn, c_next); 409147844Spjd g_gate_log(LOG_NOTICE, 410147844Spjd "Connection from %s [%s] removed.", 411147844Spjd ip2str(conn->c_srcip), conn->c_path); 412147844Spjd close(conn->c_diskfd); 413147844Spjd close(conn->c_sendfd); 414147844Spjd close(conn->c_recvfd); 415147844Spjd free(conn->c_path); 416147844Spjd free(conn); 417147844Spjd } 418128766Spjd } 419128766Spjd} 420128766Spjd 421147844Spjdstatic struct ggd_connection * 422147844Spjdconnection_find(struct g_gate_cinit *cinit) 423128766Spjd{ 424147844Spjd struct ggd_connection *conn; 425128766Spjd 426147844Spjd LIST_FOREACH(conn, &connections, c_next) { 427147844Spjd if (conn->c_token == cinit->gc_token) 428147844Spjd break; 429128766Spjd } 430147844Spjd return (conn); 431147844Spjd} 432128766Spjd 433147844Spjdstatic struct ggd_connection * 434147844Spjdconnection_new(struct g_gate_cinit *cinit, struct sockaddr *s, int sfd) 435147844Spjd{ 436147844Spjd struct ggd_connection *conn; 437147844Spjd in_addr_t ip; 438147844Spjd 439147844Spjd /* 440147844Spjd * First, look for old connections. 441147844Spjd * We probably should do it every X seconds, but what for? 442147844Spjd * It is only dangerous if an attacker wants to overload connections 443147844Spjd * queue, so here is a good place to do the cleanups. 444147844Spjd */ 445147844Spjd connection_cleanups(); 446147844Spjd 447147844Spjd conn = malloc(sizeof(*conn)); 448147844Spjd if (conn == NULL) 449147844Spjd return (NULL); 450147844Spjd conn->c_path = strdup(cinit->gc_path); 451147844Spjd if (conn->c_path == NULL) { 452147844Spjd free(conn); 453147844Spjd return (NULL); 454128766Spjd } 455147844Spjd conn->c_token = cinit->gc_token; 456147844Spjd ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); 457147844Spjd conn->c_srcip = ip; 458147844Spjd conn->c_sendfd = conn->c_recvfd = -1; 459147844Spjd if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0) 460147844Spjd conn->c_sendfd = sfd; 461147844Spjd else 462147844Spjd conn->c_recvfd = sfd; 463147844Spjd conn->c_mediasize = 0; 464147844Spjd conn->c_sectorsize = 0; 465147844Spjd time(&conn->c_birthtime); 466147844Spjd conn->c_flags = cinit->gc_flags; 467147844Spjd LIST_INSERT_HEAD(&connections, conn, c_next); 468147844Spjd g_gate_log(LOG_DEBUG, "Connection created [%s, %s].", ip2str(ip), 469147844Spjd conn->c_path); 470147844Spjd return (conn); 471147844Spjd} 472128766Spjd 473147844Spjdstatic int 474147844Spjdconnection_add(struct ggd_connection *conn, struct g_gate_cinit *cinit, 475147844Spjd struct sockaddr *s, int sfd) 476147844Spjd{ 477147844Spjd in_addr_t ip; 478147844Spjd 479147844Spjd ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); 480147844Spjd if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0) { 481147844Spjd if (conn->c_sendfd != -1) { 482147844Spjd g_gate_log(LOG_WARNING, 483147844Spjd "Send socket already exists [%s, %s].", ip2str(ip), 484147844Spjd conn->c_path); 485147844Spjd return (EEXIST); 486128766Spjd } 487147844Spjd conn->c_sendfd = sfd; 488128766Spjd } else { 489147844Spjd if (conn->c_recvfd != -1) { 490147844Spjd g_gate_log(LOG_WARNING, 491147844Spjd "Receive socket already exists [%s, %s].", 492147844Spjd ip2str(ip), conn->c_path); 493147844Spjd return (EEXIST); 494128766Spjd } 495147844Spjd conn->c_recvfd = sfd; 496128766Spjd } 497147844Spjd g_gate_log(LOG_DEBUG, "Connection added [%s, %s].", ip2str(ip), 498147844Spjd conn->c_path); 499147844Spjd return (0); 500147844Spjd} 501147844Spjd 502147844Spjd/* 503147844Spjd * Remove one socket from the given connection or the whole 504147844Spjd * connection if sfd == -1. 505147844Spjd */ 506147844Spjdstatic void 507147844Spjdconnection_remove(struct ggd_connection *conn) 508147844Spjd{ 509147844Spjd 510147844Spjd LIST_REMOVE(conn, c_next); 511147844Spjd g_gate_log(LOG_DEBUG, "Connection removed [%s %s].", 512147844Spjd ip2str(conn->c_srcip), conn->c_path); 513147844Spjd if (conn->c_sendfd != -1) 514147844Spjd close(conn->c_sendfd); 515147844Spjd if (conn->c_recvfd != -1) 516147844Spjd close(conn->c_recvfd); 517147844Spjd free(conn->c_path); 518147844Spjd free(conn); 519147844Spjd} 520147844Spjd 521147844Spjdstatic int 522147844Spjdconnection_ready(struct ggd_connection *conn) 523147844Spjd{ 524147844Spjd 525147844Spjd return (conn->c_sendfd != -1 && conn->c_recvfd != -1); 526147844Spjd} 527147844Spjd 528147844Spjdstatic void 529147844Spjdconnection_launch(struct ggd_connection *conn) 530147844Spjd{ 531147844Spjd pthread_t td; 532147844Spjd int error, pid; 533147844Spjd 534147844Spjd pid = fork(); 535147844Spjd if (pid > 0) 536147844Spjd return; 537147844Spjd else if (pid == -1) { 538147844Spjd g_gate_log(LOG_ERR, "Cannot fork: %s.", strerror(errno)); 539147844Spjd return; 540128766Spjd } 541147844Spjd g_gate_log(LOG_DEBUG, "Process created [%s].", conn->c_path); 542128766Spjd 543128766Spjd /* 544147844Spjd * Create condition variables and mutexes for in-queue and out-queue 545147844Spjd * synchronization. 546128766Spjd */ 547147844Spjd error = pthread_mutex_init(&inqueue_mtx, NULL); 548147844Spjd if (error != 0) { 549147844Spjd g_gate_xlog("pthread_mutex_init(inqueue_mtx): %s.", 550147844Spjd strerror(error)); 551147844Spjd } 552147844Spjd error = pthread_cond_init(&inqueue_cond, NULL); 553147844Spjd if (error != 0) { 554147844Spjd g_gate_xlog("pthread_cond_init(inqueue_cond): %s.", 555147844Spjd strerror(error)); 556147844Spjd } 557147844Spjd error = pthread_mutex_init(&outqueue_mtx, NULL); 558147844Spjd if (error != 0) { 559147844Spjd g_gate_xlog("pthread_mutex_init(outqueue_mtx): %s.", 560147844Spjd strerror(error)); 561147844Spjd } 562147844Spjd error = pthread_cond_init(&outqueue_cond, NULL); 563147844Spjd if (error != 0) { 564147844Spjd g_gate_xlog("pthread_cond_init(outqueue_cond): %s.", 565147844Spjd strerror(error)); 566147844Spjd } 567147844Spjd 568147844Spjd /* 569147844Spjd * Create threads: 570147844Spjd * recvtd - thread for receiving I/O request 571147844Spjd * diskio - thread for doing I/O request 572147844Spjd * sendtd - thread for sending I/O requests back 573147844Spjd */ 574147844Spjd error = pthread_create(&td, NULL, send_thread, conn); 575147844Spjd if (error != 0) { 576147844Spjd g_gate_xlog("pthread_create(send_thread): %s.", 577147844Spjd strerror(error)); 578147844Spjd } 579147844Spjd error = pthread_create(&td, NULL, recv_thread, conn); 580147844Spjd if (error != 0) { 581147844Spjd g_gate_xlog("pthread_create(recv_thread): %s.", 582147844Spjd strerror(error)); 583147844Spjd } 584147844Spjd disk_thread(conn); 585147844Spjd} 586147844Spjd 587147844Spjdstatic void 588147844Spjdsendfail(int sfd, int error, const char *fmt, ...) 589147844Spjd{ 590147844Spjd struct g_gate_sinit sinit; 591147844Spjd va_list ap; 592147844Spjd ssize_t data; 593147844Spjd 594147844Spjd sinit.gs_error = error; 595128766Spjd g_gate_swap2n_sinit(&sinit); 596147844Spjd data = g_gate_send(sfd, &sinit, sizeof(sinit), 0); 597128766Spjd g_gate_swap2h_sinit(&sinit); 598147844Spjd if (data != sizeof(sinit)) { 599147844Spjd g_gate_log(LOG_WARNING, "Cannot send initial packet: %s.", 600128766Spjd strerror(errno)); 601147844Spjd return; 602128766Spjd } 603147844Spjd if (fmt != NULL) { 604147844Spjd va_start(ap, fmt); 605147844Spjd g_gate_vlog(LOG_WARNING, fmt, ap); 606147844Spjd va_end(ap); 607147844Spjd } 608147844Spjd} 609128766Spjd 610147844Spjdstatic void * 611147844Spjdmalloc_waitok(size_t size) 612147844Spjd{ 613147844Spjd void *p; 614128766Spjd 615147844Spjd while ((p = malloc(size)) == NULL) { 616147844Spjd g_gate_log(LOG_DEBUG, "Cannot allocate %zu bytes.", size); 617147844Spjd sleep(1); 618147844Spjd } 619147844Spjd return (p); 620147844Spjd} 621128766Spjd 622147844Spjdstatic void * 623147844Spjdrecv_thread(void *arg) 624147844Spjd{ 625147844Spjd struct ggd_connection *conn; 626147844Spjd struct ggd_request *req; 627147844Spjd ssize_t data; 628147844Spjd int error, fd; 629147844Spjd 630147844Spjd conn = arg; 631147844Spjd g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); 632147844Spjd fd = conn->c_recvfd; 633128766Spjd for (;;) { 634128766Spjd /* 635147844Spjd * Get header packet. 636128766Spjd */ 637147844Spjd req = malloc_waitok(sizeof(*req)); 638147844Spjd data = g_gate_recv(fd, &req->r_hdr, sizeof(req->r_hdr), 639147844Spjd MSG_WAITALL); 640128766Spjd if (data == 0) { 641128766Spjd g_gate_log(LOG_DEBUG, "Process %u exiting.", getpid()); 642128766Spjd exit(EXIT_SUCCESS); 643128766Spjd } else if (data == -1) { 644128766Spjd g_gate_xlog("Error while receiving hdr packet: %s.", 645128766Spjd strerror(errno)); 646147844Spjd } else if (data != sizeof(req->r_hdr)) { 647128766Spjd g_gate_xlog("Malformed hdr packet received."); 648128766Spjd } 649128766Spjd g_gate_log(LOG_DEBUG, "Received hdr packet."); 650147844Spjd g_gate_swap2h_hdr(&req->r_hdr); 651128766Spjd 652147844Spjd g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, 653147844Spjd (intmax_t)req->r_offset, (unsigned)req->r_length); 654147844Spjd 655128766Spjd /* 656147844Spjd * Allocate memory for data. 657128766Spjd */ 658147844Spjd req->r_data = malloc_waitok(req->r_length); 659128766Spjd 660147844Spjd /* 661147844Spjd * Receive data to write for WRITE request. 662147844Spjd */ 663147844Spjd if (req->r_cmd == GGATE_CMD_WRITE) { 664128766Spjd g_gate_log(LOG_DEBUG, "Waiting for %u bytes of data...", 665147844Spjd req->r_length); 666147844Spjd data = g_gate_recv(fd, req->r_data, req->r_length, 667147844Spjd MSG_WAITALL); 668128766Spjd if (data == -1) { 669128766Spjd g_gate_xlog("Error while receiving data: %s.", 670128766Spjd strerror(errno)); 671128766Spjd } 672147844Spjd } 673147844Spjd 674147844Spjd /* 675147844Spjd * Put the request onto the incoming queue. 676147844Spjd */ 677147844Spjd error = pthread_mutex_lock(&inqueue_mtx); 678147844Spjd assert(error == 0); 679147844Spjd TAILQ_INSERT_TAIL(&inqueue, req, r_next); 680147844Spjd error = pthread_cond_signal(&inqueue_cond); 681147844Spjd assert(error == 0); 682147844Spjd error = pthread_mutex_unlock(&inqueue_mtx); 683147844Spjd assert(error == 0); 684147844Spjd } 685147844Spjd} 686147844Spjd 687147844Spjdstatic void * 688147844Spjddisk_thread(void *arg) 689147844Spjd{ 690147844Spjd struct ggd_connection *conn; 691147844Spjd struct ggd_request *req; 692147844Spjd ssize_t data; 693147844Spjd int error, fd; 694147844Spjd 695147844Spjd conn = arg; 696147844Spjd g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); 697147844Spjd fd = conn->c_diskfd; 698147844Spjd for (;;) { 699147844Spjd /* 700147844Spjd * Get a request from the incoming queue. 701147844Spjd */ 702147844Spjd error = pthread_mutex_lock(&inqueue_mtx); 703147844Spjd assert(error == 0); 704147844Spjd while ((req = TAILQ_FIRST(&inqueue)) == NULL) { 705147844Spjd error = pthread_cond_wait(&inqueue_cond, &inqueue_mtx); 706147844Spjd assert(error == 0); 707147844Spjd } 708147844Spjd TAILQ_REMOVE(&inqueue, req, r_next); 709147844Spjd error = pthread_mutex_unlock(&inqueue_mtx); 710147844Spjd assert(error == 0); 711147844Spjd 712147844Spjd /* 713147844Spjd * Check the request. 714147844Spjd */ 715147844Spjd assert(req->r_cmd == GGATE_CMD_READ || req->r_cmd == GGATE_CMD_WRITE); 716147844Spjd assert(req->r_offset + req->r_length <= (uintmax_t)conn->c_mediasize); 717147844Spjd assert((req->r_offset % conn->c_sectorsize) == 0); 718147844Spjd assert((req->r_length % conn->c_sectorsize) == 0); 719147844Spjd 720147844Spjd g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, 721147844Spjd (intmax_t)req->r_offset, (unsigned)req->r_length); 722147844Spjd 723147844Spjd /* 724147844Spjd * Do the request. 725147844Spjd */ 726147844Spjd data = 0; 727147844Spjd switch (req->r_cmd) { 728147844Spjd case GGATE_CMD_READ: 729147844Spjd data = pread(fd, req->r_data, req->r_length, 730147844Spjd req->r_offset); 731147844Spjd break; 732147844Spjd case GGATE_CMD_WRITE: 733147844Spjd data = pwrite(fd, req->r_data, req->r_length, 734147844Spjd req->r_offset); 735147844Spjd /* Free data memory here - better sooner. */ 736147844Spjd free(req->r_data); 737147844Spjd req->r_data = NULL; 738147844Spjd break; 739147844Spjd } 740147844Spjd if (data != (ssize_t)req->r_length) { 741147844Spjd /* Report short reads/writes as I/O errors. */ 742147844Spjd if (errno == 0) 743147844Spjd errno = EIO; 744147844Spjd g_gate_log(LOG_ERR, "Disk error: %s", strerror(errno)); 745147844Spjd req->r_error = errno; 746147844Spjd if (req->r_data != NULL) { 747147844Spjd free(req->r_data); 748147844Spjd req->r_data = NULL; 749128766Spjd } 750147844Spjd } 751147844Spjd 752147844Spjd /* 753147844Spjd * Put the request onto the outgoing queue. 754147844Spjd */ 755147844Spjd error = pthread_mutex_lock(&outqueue_mtx); 756147844Spjd assert(error == 0); 757147844Spjd TAILQ_INSERT_TAIL(&outqueue, req, r_next); 758147844Spjd error = pthread_cond_signal(&outqueue_cond); 759147844Spjd assert(error == 0); 760147844Spjd error = pthread_mutex_unlock(&outqueue_mtx); 761147844Spjd assert(error == 0); 762147844Spjd } 763180020Smtm 764180020Smtm /* NOTREACHED */ 765180020Smtm return (NULL); 766147844Spjd} 767147844Spjd 768147844Spjdstatic void * 769147844Spjdsend_thread(void *arg) 770147844Spjd{ 771147844Spjd struct ggd_connection *conn; 772147844Spjd struct ggd_request *req; 773147844Spjd ssize_t data; 774147844Spjd int error, fd; 775147844Spjd 776147844Spjd conn = arg; 777147844Spjd g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); 778147844Spjd fd = conn->c_sendfd; 779147844Spjd for (;;) { 780147844Spjd /* 781147844Spjd * Get a request from the outgoing queue. 782147844Spjd */ 783147844Spjd error = pthread_mutex_lock(&outqueue_mtx); 784147844Spjd assert(error == 0); 785147844Spjd while ((req = TAILQ_FIRST(&outqueue)) == NULL) { 786147844Spjd error = pthread_cond_wait(&outqueue_cond, 787147844Spjd &outqueue_mtx); 788147844Spjd assert(error == 0); 789147844Spjd } 790147844Spjd TAILQ_REMOVE(&outqueue, req, r_next); 791147844Spjd error = pthread_mutex_unlock(&outqueue_mtx); 792147844Spjd assert(error == 0); 793147844Spjd 794147844Spjd g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, 795147844Spjd (intmax_t)req->r_offset, (unsigned)req->r_length); 796147844Spjd 797147844Spjd /* 798147844Spjd * Send the request. 799147844Spjd */ 800147844Spjd g_gate_swap2n_hdr(&req->r_hdr); 801147844Spjd if (g_gate_send(fd, &req->r_hdr, sizeof(req->r_hdr), 0) == -1) { 802147844Spjd g_gate_xlog("Error while sending hdr packet: %s.", 803147844Spjd strerror(errno)); 804147844Spjd } 805147844Spjd g_gate_log(LOG_DEBUG, "Sent hdr packet."); 806147844Spjd g_gate_swap2h_hdr(&req->r_hdr); 807147844Spjd if (req->r_data != NULL) { 808147844Spjd data = g_gate_send(fd, req->r_data, req->r_length, 0); 809147844Spjd if (data != (ssize_t)req->r_length) { 810147844Spjd g_gate_xlog("Error while sending data: %s.", 811128766Spjd strerror(errno)); 812128766Spjd } 813147844Spjd g_gate_log(LOG_DEBUG, 814147844Spjd "Sent %zd bytes (offset=%ju, size=%zu).", data, 815147844Spjd (uintmax_t)req->r_offset, (size_t)req->r_length); 816147844Spjd free(req->r_data); 817128766Spjd } 818147844Spjd free(req); 819128766Spjd } 820180020Smtm 821180020Smtm /* NOTREACHED */ 822180020Smtm return (NULL); 823128766Spjd} 824128766Spjd 825128766Spjdstatic void 826147844Spjdlog_connection(struct sockaddr *from) 827147844Spjd{ 828147844Spjd in_addr_t ip; 829147844Spjd 830147844Spjd ip = htonl(((struct sockaddr_in *)(void *)from)->sin_addr.s_addr); 831147844Spjd g_gate_log(LOG_INFO, "Connection from: %s.", ip2str(ip)); 832147844Spjd} 833147844Spjd 834147844Spjdstatic int 835147844Spjdhandshake(struct sockaddr *from, int sfd) 836147844Spjd{ 837147844Spjd struct g_gate_version ver; 838147844Spjd struct g_gate_cinit cinit; 839147844Spjd struct g_gate_sinit sinit; 840147844Spjd struct ggd_connection *conn; 841147844Spjd struct ggd_export *ex; 842147844Spjd ssize_t data; 843147844Spjd 844147844Spjd log_connection(from); 845147844Spjd /* 846147844Spjd * Phase 1: Version verification. 847147844Spjd */ 848147844Spjd g_gate_log(LOG_DEBUG, "Receiving version packet."); 849147844Spjd data = g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL); 850147844Spjd g_gate_swap2h_version(&ver); 851147844Spjd if (data != sizeof(ver)) { 852147844Spjd g_gate_log(LOG_WARNING, "Malformed version packet."); 853147844Spjd return (0); 854147844Spjd } 855147844Spjd g_gate_log(LOG_DEBUG, "Version packet received."); 856147844Spjd if (memcmp(ver.gv_magic, GGATE_MAGIC, strlen(GGATE_MAGIC)) != 0) { 857147844Spjd g_gate_log(LOG_WARNING, "Invalid magic field."); 858147844Spjd return (0); 859147844Spjd } 860147844Spjd if (ver.gv_version != GGATE_VERSION) { 861147844Spjd g_gate_log(LOG_WARNING, "Version %u is not supported.", 862147844Spjd ver.gv_version); 863147844Spjd return (0); 864147844Spjd } 865147844Spjd ver.gv_error = 0; 866147844Spjd g_gate_swap2n_version(&ver); 867147844Spjd data = g_gate_send(sfd, &ver, sizeof(ver), 0); 868147844Spjd g_gate_swap2h_version(&ver); 869147844Spjd if (data == -1) { 870147844Spjd sendfail(sfd, errno, "Error while sending version packet: %s.", 871147844Spjd strerror(errno)); 872147844Spjd return (0); 873147844Spjd } 874147844Spjd 875147844Spjd /* 876147844Spjd * Phase 2: Request verification. 877147844Spjd */ 878147844Spjd g_gate_log(LOG_DEBUG, "Receiving initial packet."); 879147844Spjd data = g_gate_recv(sfd, &cinit, sizeof(cinit), MSG_WAITALL); 880147844Spjd g_gate_swap2h_cinit(&cinit); 881147844Spjd if (data != sizeof(cinit)) { 882147844Spjd g_gate_log(LOG_WARNING, "Malformed initial packet."); 883147844Spjd return (0); 884147844Spjd } 885147844Spjd g_gate_log(LOG_DEBUG, "Initial packet received."); 886147844Spjd conn = connection_find(&cinit); 887147844Spjd if (conn != NULL) { 888147844Spjd /* 889147844Spjd * Connection should already exists. 890147844Spjd */ 891147844Spjd g_gate_log(LOG_DEBUG, "Found existing connection (token=%lu).", 892147844Spjd (unsigned long)conn->c_token); 893147844Spjd if (connection_add(conn, &cinit, from, sfd) == -1) { 894147844Spjd connection_remove(conn); 895147844Spjd return (0); 896147844Spjd } 897147844Spjd } else { 898147844Spjd /* 899147844Spjd * New connection, allocate space. 900147844Spjd */ 901147844Spjd conn = connection_new(&cinit, from, sfd); 902147844Spjd if (conn == NULL) { 903147844Spjd sendfail(sfd, ENOMEM, 904147844Spjd "Cannot allocate new connection."); 905147844Spjd return (0); 906147844Spjd } 907147844Spjd g_gate_log(LOG_DEBUG, "New connection created (token=%lu).", 908147844Spjd (unsigned long)conn->c_token); 909147844Spjd } 910147844Spjd 911147844Spjd ex = exports_find(from, &cinit, conn); 912147844Spjd if (ex == NULL) { 913285529Sbrueffer sendfail(sfd, errno, NULL); 914147844Spjd connection_remove(conn); 915147844Spjd return (0); 916147844Spjd } 917147844Spjd if (conn->c_mediasize == 0) { 918147844Spjd conn->c_mediasize = g_gate_mediasize(conn->c_diskfd); 919147844Spjd conn->c_sectorsize = g_gate_sectorsize(conn->c_diskfd); 920147844Spjd } 921147844Spjd sinit.gs_mediasize = conn->c_mediasize; 922147844Spjd sinit.gs_sectorsize = conn->c_sectorsize; 923147844Spjd sinit.gs_error = 0; 924147844Spjd 925147844Spjd g_gate_log(LOG_DEBUG, "Sending initial packet."); 926147844Spjd 927147844Spjd g_gate_swap2n_sinit(&sinit); 928147844Spjd data = g_gate_send(sfd, &sinit, sizeof(sinit), 0); 929147844Spjd g_gate_swap2h_sinit(&sinit); 930147844Spjd if (data == -1) { 931147844Spjd sendfail(sfd, errno, "Error while sending initial packet: %s.", 932147844Spjd strerror(errno)); 933147844Spjd return (0); 934147844Spjd } 935147844Spjd 936147844Spjd if (connection_ready(conn)) { 937147844Spjd connection_launch(conn); 938147844Spjd connection_remove(conn); 939147844Spjd } 940147844Spjd return (1); 941147844Spjd} 942147844Spjd 943147844Spjdstatic void 944128766Spjdhuphandler(int sig __unused) 945128766Spjd{ 946128766Spjd 947128766Spjd got_sighup = 1; 948128766Spjd} 949128766Spjd 950128766Spjdint 951128766Spjdmain(int argc, char *argv[]) 952128766Spjd{ 953294973Sngie const char *ggated_pidfile = _PATH_VARRUN "/ggated.pid"; 954294973Sngie struct pidfh *pfh; 955128766Spjd struct sockaddr_in serv; 956128766Spjd struct sockaddr from; 957128766Spjd socklen_t fromlen; 958294973Sngie pid_t otherpid; 959294973Sngie int ch, sfd, tmpsfd; 960147844Spjd unsigned port; 961128766Spjd 962128766Spjd bindaddr = htonl(INADDR_ANY); 963128766Spjd port = G_GATE_PORT; 964294973Sngie while ((ch = getopt(argc, argv, "a:hnp:F:R:S:v")) != -1) { 965128766Spjd switch (ch) { 966128766Spjd case 'a': 967128766Spjd bindaddr = g_gate_str2ip(optarg); 968128766Spjd if (bindaddr == INADDR_NONE) { 969128766Spjd errx(EXIT_FAILURE, 970128766Spjd "Invalid IP/host name to bind to."); 971128766Spjd } 972128766Spjd break; 973294973Sngie case 'F': 974294973Sngie ggated_pidfile = optarg; 975294973Sngie break; 976128766Spjd case 'n': 977128766Spjd nagle = 0; 978128766Spjd break; 979128766Spjd case 'p': 980128766Spjd errno = 0; 981128766Spjd port = strtoul(optarg, NULL, 10); 982128766Spjd if (port == 0 && errno != 0) 983128766Spjd errx(EXIT_FAILURE, "Invalid port."); 984128766Spjd break; 985128766Spjd case 'R': 986128766Spjd errno = 0; 987128766Spjd rcvbuf = strtoul(optarg, NULL, 10); 988128766Spjd if (rcvbuf == 0 && errno != 0) 989128766Spjd errx(EXIT_FAILURE, "Invalid rcvbuf."); 990128766Spjd break; 991128766Spjd case 'S': 992128766Spjd errno = 0; 993128766Spjd sndbuf = strtoul(optarg, NULL, 10); 994128766Spjd if (sndbuf == 0 && errno != 0) 995128766Spjd errx(EXIT_FAILURE, "Invalid sndbuf."); 996128766Spjd break; 997128766Spjd case 'v': 998128766Spjd g_gate_verbose++; 999128766Spjd break; 1000128766Spjd case 'h': 1001128766Spjd default: 1002128766Spjd usage(); 1003128766Spjd } 1004128766Spjd } 1005128766Spjd argc -= optind; 1006128766Spjd argv += optind; 1007128766Spjd 1008128766Spjd if (argv[0] != NULL) 1009147844Spjd exports_file = argv[0]; 1010128766Spjd exports_get(); 1011128766Spjd 1012294973Sngie pfh = pidfile_open(ggated_pidfile, 0600, &otherpid); 1013294973Sngie if (pfh == NULL) { 1014294973Sngie if (errno == EEXIST) { 1015294973Sngie errx(EXIT_FAILURE, "Daemon already running, pid: %jd.", 1016294973Sngie (intmax_t)otherpid); 1017294973Sngie } 1018294973Sngie err(EXIT_FAILURE, "Cannot open/create pidfile"); 1019294973Sngie } 1020294973Sngie 1021128766Spjd if (!g_gate_verbose) { 1022128766Spjd /* Run in daemon mode. */ 1023134937Spjd if (daemon(0, 0) == -1) 1024147844Spjd g_gate_xlog("Cannot daemonize: %s", strerror(errno)); 1025128766Spjd } 1026128766Spjd 1027294973Sngie pidfile_write(pfh); 1028294973Sngie 1029128766Spjd signal(SIGCHLD, SIG_IGN); 1030128766Spjd 1031128766Spjd sfd = socket(AF_INET, SOCK_STREAM, 0); 1032134937Spjd if (sfd == -1) 1033147844Spjd g_gate_xlog("Cannot open stream socket: %s.", strerror(errno)); 1034128766Spjd bzero(&serv, sizeof(serv)); 1035128766Spjd serv.sin_family = AF_INET; 1036128766Spjd serv.sin_addr.s_addr = bindaddr; 1037128766Spjd serv.sin_port = htons(port); 1038147844Spjd 1039147844Spjd g_gate_socket_settings(sfd); 1040147844Spjd 1041134937Spjd if (bind(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) 1042128766Spjd g_gate_xlog("bind(): %s.", strerror(errno)); 1043134937Spjd if (listen(sfd, 5) == -1) 1044128766Spjd g_gate_xlog("listen(): %s.", strerror(errno)); 1045128766Spjd 1046128766Spjd g_gate_log(LOG_INFO, "Listen on port: %d.", port); 1047128766Spjd 1048128766Spjd signal(SIGHUP, huphandler); 1049128766Spjd 1050128766Spjd for (;;) { 1051128766Spjd fromlen = sizeof(from); 1052128766Spjd tmpsfd = accept(sfd, &from, &fromlen); 1053134937Spjd if (tmpsfd == -1) 1054128766Spjd g_gate_xlog("accept(): %s.", strerror(errno)); 1055128766Spjd 1056128766Spjd if (got_sighup) { 1057128766Spjd got_sighup = 0; 1058128766Spjd exports_get(); 1059128766Spjd } 1060128766Spjd 1061147844Spjd if (!handshake(&from, tmpsfd)) 1062128766Spjd close(tmpsfd); 1063128766Spjd } 1064128766Spjd close(sfd); 1065294973Sngie pidfile_remove(pfh); 1066128766Spjd exit(EXIT_SUCCESS); 1067128766Spjd} 1068