/*- * Copyright (c) 2004 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ggate.h" int g_gate_devfd = -1; int g_gate_verbose = 0; void g_gate_vlog(int priority, const char *message, va_list ap) { if (g_gate_verbose) { const char *prefix; switch (priority) { case LOG_ERR: prefix = "error"; break; case LOG_WARNING: prefix = "warning"; break; case LOG_NOTICE: prefix = "notice"; break; case LOG_INFO: prefix = "info"; break; case LOG_DEBUG: prefix = "debug"; break; default: prefix = "unknown"; } printf("%s: ", prefix); vprintf(message, ap); printf("\n"); } else { if (priority != LOG_DEBUG) vsyslog(priority, message, ap); } } void g_gate_log(int priority, const char *message, ...) { va_list ap; va_start(ap, message); g_gate_vlog(priority, message, ap); va_end(ap); } void g_gate_xvlog(const char *message, va_list ap) { g_gate_vlog(LOG_ERR, message, ap); g_gate_vlog(LOG_ERR, "Exiting.", ap); exit(EXIT_FAILURE); } void g_gate_xlog(const char *message, ...) { va_list ap; va_start(ap, message); g_gate_xvlog(message, ap); /* NOTREACHED */ va_end(ap); exit(EXIT_FAILURE); } off_t g_gate_mediasize(int fd) { off_t mediasize; struct stat sb; if (fstat(fd, &sb) == -1) g_gate_xlog("fstat(): %s.", strerror(errno)); if (S_ISCHR(sb.st_mode)) { if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1) { g_gate_xlog("Can't get media size: %s.", strerror(errno)); } } else if (S_ISREG(sb.st_mode)) { mediasize = sb.st_size; } else { g_gate_xlog("Unsupported file system object."); } return (mediasize); } unsigned g_gate_sectorsize(int fd) { unsigned secsize; struct stat sb; if (fstat(fd, &sb) == -1) g_gate_xlog("fstat(): %s.", strerror(errno)); if (S_ISCHR(sb.st_mode)) { if (ioctl(fd, DIOCGSECTORSIZE, &secsize) == -1) { g_gate_xlog("Can't get sector size: %s.", strerror(errno)); } } else if (S_ISREG(sb.st_mode)) { secsize = 512; } else { g_gate_xlog("Unsupported file system object."); } return (secsize); } void g_gate_open_device(void) { g_gate_devfd = open("/dev/" G_GATE_CTL_NAME, O_RDWR); if (g_gate_devfd == -1) err(EXIT_FAILURE, "open(/dev/%s)", G_GATE_CTL_NAME); } void g_gate_close_device(void) { close(g_gate_devfd); } void g_gate_ioctl(unsigned long req, void *data) { if (ioctl(g_gate_devfd, req, data) == -1) { g_gate_xlog("%s: ioctl(/dev/%s): %s.", getprogname(), G_GATE_CTL_NAME, strerror(errno)); } } void g_gate_destroy(int unit, int force) { struct g_gate_ctl_destroy ggio; ggio.gctl_version = G_GATE_VERSION; ggio.gctl_unit = unit; ggio.gctl_force = force; g_gate_ioctl(G_GATE_CMD_DESTROY, &ggio); } void g_gate_load_module(void) { if (modfind("g_gate") == -1) { /* Not present in kernel, try loading it. */ if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) { if (errno != EEXIST) { errx(EXIT_FAILURE, "geom_gate module not available!"); } } } } /* * When we send from ggatec packets larger than 32kB, performance drops * significantly (eg. to 256kB/s over 1Gbit/s link). This is not a problem * when data is send from ggated. I don't know why, so for now I limit * size of packets send from ggatec to 32kB by defining MAX_SEND_SIZE * in ggatec Makefile. */ #ifndef MAX_SEND_SIZE #define MAX_SEND_SIZE MAXPHYS #endif ssize_t g_gate_send(int s, const void *buf, size_t len, int flags) { ssize_t done = 0, done2; const unsigned char *p = buf; while (len > 0) { done2 = send(s, p, MIN(len, MAX_SEND_SIZE), flags); if (done2 == 0) break; else if (done2 == -1) { if (errno == EAGAIN) { printf("%s: EAGAIN\n", __func__); continue; } done = -1; break; } done += done2; p += done2; len -= done2; } return (done); } ssize_t g_gate_recv(int s, void *buf, size_t len, int flags) { ssize_t done; do { done = recv(s, buf, len, flags); } while (done == -1 && errno == EAGAIN); return (done); } int nagle = 1; unsigned rcvbuf = G_GATE_RCVBUF; unsigned sndbuf = G_GATE_SNDBUF; void g_gate_socket_settings(int sfd) { struct timeval tv; int bsize, on; /* Socket settings. */ on = 1; if (nagle) { if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == -1) { g_gate_xlog("setsockopt() error: %s.", strerror(errno)); } } if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) g_gate_xlog("setsockopt(SO_REUSEADDR): %s.", strerror(errno)); bsize = rcvbuf; if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) == -1) g_gate_xlog("setsockopt(SO_RCVBUF): %s.", strerror(errno)); bsize = sndbuf; if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &bsize, sizeof(bsize)) == -1) g_gate_xlog("setsockopt(SO_SNDBUF): %s.", strerror(errno)); tv.tv_sec = 8; tv.tv_usec = 0; if (setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) { g_gate_log(LOG_ERR, "setsockopt(SO_SNDTIMEO) error: %s.", strerror(errno)); } if (setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { g_gate_log(LOG_ERR, "setsockopt(SO_RCVTIMEO) error: %s.", strerror(errno)); } } #ifdef LIBGEOM static struct gclass * find_class(struct gmesh *mesh, const char *name) { struct gclass *class; LIST_FOREACH(class, &mesh->lg_class, lg_class) { if (strcmp(class->lg_name, name) == 0) return (class); } return (NULL); } static const char * get_conf(struct ggeom *gp, const char *name) { struct gconfig *conf; LIST_FOREACH(conf, &gp->lg_config, lg_config) { if (strcmp(conf->lg_name, name) == 0) return (conf->lg_val); } return (NULL); } static void show_config(struct ggeom *gp, int verbose) { struct gprovider *pp; char buf[5]; pp = LIST_FIRST(&gp->lg_provider); if (pp == NULL) return; if (!verbose) { printf("%s\n", pp->lg_name); return; } printf(" NAME: %s\n", pp->lg_name); printf(" info: %s\n", get_conf(gp, "info")); printf(" access: %s\n", get_conf(gp, "access")); printf(" timeout: %s\n", get_conf(gp, "timeout")); printf("queue_count: %s\n", get_conf(gp, "queue_count")); printf(" queue_size: %s\n", get_conf(gp, "queue_size")); printf(" references: %s\n", get_conf(gp, "ref")); humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); printf(" mediasize: %jd (%s)\n", (intmax_t)pp->lg_mediasize, buf); printf(" sectorsize: %u\n", pp->lg_sectorsize); printf(" mode: %s\n", pp->lg_mode); printf("\n"); } void g_gate_list(int unit, int verbose) { struct gmesh mesh; struct gclass *class; struct ggeom *gp; char name[64]; int error; error = geom_gettree(&mesh); if (error != 0) exit(EXIT_FAILURE); class = find_class(&mesh, G_GATE_CLASS_NAME); if (class == NULL) { geom_deletetree(&mesh); exit(EXIT_SUCCESS); } if (unit >= 0) { snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME, unit); } LIST_FOREACH(gp, &class->lg_geom, lg_geom) { if (unit != -1 && strcmp(gp->lg_name, name) != 0) continue; show_config(gp, verbose); } geom_deletetree(&mesh); exit(EXIT_SUCCESS); } #endif /* LIBGEOM */ in_addr_t g_gate_str2ip(const char *str) { struct hostent *hp; in_addr_t ip; ip = inet_addr(str); if (ip != INADDR_NONE) { /* It is a valid IP address. */ return (ip); } /* Check if it is a valid host name. */ hp = gethostbyname(str); if (hp == NULL) return (INADDR_NONE); return (((struct in_addr *)(void *)hp->h_addr)->s_addr); }