1121663Sharti/* 2121663Sharti * Copyright (c) 2001-2003 3121663Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4121663Sharti * All rights reserved. 5121663Sharti * 6131823Sharti * Author: Harti Brandt <harti@freebsd.org> 7131823Sharti * 8121663Sharti * Redistribution and use in source and binary forms, with or without 9121663Sharti * modification, are permitted provided that the following conditions 10121663Sharti * are met: 11121663Sharti * 1. Redistributions of source code must retain the above copyright 12121663Sharti * notice, this list of conditions and the following disclaimer. 13121663Sharti * 2. Redistributions in binary form must reproduce the above copyright 14121663Sharti * notice, this list of conditions and the following disclaimer in the 15121663Sharti * documentation and/or other materials provided with the distribution. 16121663Sharti * 17121663Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18121663Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19121663Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20121663Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21121663Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22121663Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23121663Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24121663Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25121663Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26121663Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27121663Sharti * SUCH DAMAGE. 28121663Sharti * 29146532Sharti * $Begemot: libunimsg/sscop/common.c,v 1.5 2005/05/23 11:46:16 brandt_h Exp $ 30121663Sharti */ 31121663Sharti 32121663Sharti#include <sys/types.h> 33121663Sharti#include <sys/socket.h> 34121663Sharti#include <sys/uio.h> 35121663Sharti 36121663Sharti#include <stdio.h> 37121663Sharti#include <stdlib.h> 38121663Sharti#include <stdarg.h> 39121663Sharti#include <string.h> 40121663Sharti#include <errno.h> 41121663Sharti#include <unistd.h> 42121663Sharti#include <time.h> 43121663Sharti#include <signal.h> 44121663Sharti#include <assert.h> 45121663Sharti#include <fcntl.h> 46121663Sharti#include <err.h> 47121663Sharti 48121663Sharti#include <netnatm/unimsg.h> 49121663Sharti#include <netnatm/saal/sscop.h> 50121663Sharti#include "common.h" 51121663Sharti 52121663Shartistruct timer { 53121663Sharti evTimerID id; 54121663Sharti struct sscop *sscop; 55121663Sharti void (*func)(void *); 56121663Sharti}; 57121663Sharti 58121663Shartiint useframe; 59121663Shartiint sscopframe; 60121663Shartiu_int sscop_vflag; 61121663Shartiint sscop_fd; 62121663Shartiint user_fd; 63121663Shartiint loose; 64121663Shartiint user_out_fd; 65121663Shartiu_int verbose; 66135923Strhodes#ifndef USE_LIBBEGEMOT 67121663ShartievContext evctx; 68135923Strhodes#endif 69121663ShartievFileID sscop_h; 70121663ShartievFileID user_h; 71121663Sharti 72121663Sharti/* 73121663Sharti * This function get's called from sscop to put out verbose messages 74121663Sharti */ 75121663Shartivoid 76121663Shartisscop_verbose(struct sscop *sscop __unused, void *u __unused, 77121663Sharti const char *fmt, ...) 78121663Sharti{ 79121663Sharti va_list ap; 80121663Sharti 81121663Sharti va_start(ap, fmt); 82121663Sharti vfprintf(stderr, fmt, ap); 83121663Sharti fprintf(stderr, "\n"); 84121663Sharti va_end(ap); 85121663Sharti} 86121663Shartivoid 87121663Shartiverb(const char *fmt, ...) 88121663Sharti{ 89121663Sharti va_list ap; 90121663Sharti 91121663Sharti va_start(ap, fmt); 92121663Sharti vfprintf(stderr, fmt, ap); 93121663Sharti fprintf(stderr, "\n"); 94121663Sharti va_end(ap); 95121663Sharti} 96121663Sharti 97121663Sharti/* 98121663Sharti * Dump a buffer in hex to stderr. 99121663Sharti */ 100121663Shartivoid 101121663Shartidump_buf(const char *w, const u_char *buf, size_t len) 102121663Sharti{ 103121663Sharti u_int i; 104121663Sharti 105121663Sharti fprintf(stderr, "%s %zu: ", w, len); 106121663Sharti for(i = 0; i < len; i++) { 107121663Sharti if (i % 4 == 0 && i != 0) 108121663Sharti fprintf(stderr, " "); 109121663Sharti fprintf(stderr, "%02x", *buf++); 110121663Sharti } 111121663Sharti fprintf(stderr, "\n"); 112121663Sharti} 113121663Sharti 114121663Sharti/* 115121663Sharti * SSCOP file descriptor is ready. Allocate and read one message 116121663Sharti * and dispatch a signal. 117121663Sharti */ 118121663Shartistruct uni_msg * 119121663Shartiproto_msgin(int fd __unused) 120121663Sharti{ 121121663Sharti struct uni_msg *m = NULL; 122121663Sharti ssize_t size; 123121663Sharti u_int32_t flen; 124121663Sharti u_int got; 125121663Sharti 126121663Sharti if (sscopframe) { 127121663Sharti if ((size = read(sscop_fd, &flen, 4)) == -1) 128121663Sharti err(1, "error reading frame hdr"); 129121663Sharti if (size == 0) { 130121663Sharti got = 0; 131121663Sharti goto eof; 132121663Sharti } 133121663Sharti if (size != 4) 134121663Sharti errx(1, "short frame header: %zd", size); 135121663Sharti if ((m = uni_msg_alloc(flen)) == NULL) 136121663Sharti err(1, NULL); 137121663Sharti for (got = 0; got < flen; got += (size_t)size) { 138121663Sharti size = read(sscop_fd, m->b_rptr + got, flen - got); 139121663Sharti if (size == -1) 140121663Sharti err(1, "error reading frame"); 141121663Sharti if (size == 0) { 142121663Sharti got = 0; 143121663Sharti break; 144121663Sharti } 145121663Sharti } 146121663Sharti 147121663Sharti } else { 148121663Sharti if ((m = uni_msg_alloc(MAXMSG)) == NULL) 149121663Sharti err(1, NULL); 150121663Sharti if ((size = read(sscop_fd, m->b_rptr, MAXMSG)) == -1) 151121663Sharti err(1, "error reading message"); 152121663Sharti got = size; 153121663Sharti } 154121663Sharti 155121663Sharti if (got == 0) { 156121663Sharti eof: 157135923Strhodes#ifdef USE_LIBBEGEMOT 158135923Strhodes poll_unregister(sscop_h); 159135923Strhodes#else 160121663Sharti evDeselectFD(evctx, sscop_h); 161135923Strhodes#endif 162121663Sharti (void)close(sscop_fd); 163121663Sharti sscop_fd = -1; 164121663Sharti if (m != NULL) 165121663Sharti uni_msg_destroy(m); 166121663Sharti VERBOSE(("EOF on sscop file descriptor")); 167121663Sharti return (NULL); 168121663Sharti } 169121663Sharti m->b_wptr = m->b_rptr + got; 170121663Sharti 171121663Sharti if(verbose & 0x0002) 172121663Sharti dump_buf("SSCOP INPUT", m->b_rptr, got); 173121663Sharti 174121663Sharti return (m); 175121663Sharti} 176121663Sharti 177121663Sharti/* 178121663Sharti * User file descriptor ready - read a message 179121663Sharti */ 180121663Shartistruct uni_msg * 181121663Shartiuser_msgin(int fd __unused) 182121663Sharti{ 183121663Sharti struct uni_msg *m = NULL; 184121663Sharti ssize_t size; 185121663Sharti u_int32_t flen; 186121663Sharti u_int got; 187121663Sharti 188121663Sharti if (useframe) { 189121663Sharti if ((size = read(user_fd, &flen, 4)) == -1) 190121663Sharti err(1, "error reading frame hdr"); 191121663Sharti if (size == 0) { 192121663Sharti got = 0; 193121663Sharti goto eof; 194121663Sharti } 195121663Sharti if (size != 4) 196121663Sharti errx(1, "short frame header: %zd", size); 197121663Sharti if ((m = uni_msg_alloc(flen)) == NULL) 198121663Sharti err(1, NULL); 199121663Sharti for (got = 0; got < flen; got++) { 200121663Sharti size = read(user_fd, m->b_rptr + got, flen - got); 201121663Sharti if (size == -1) 202121663Sharti err(1, "error reading frame"); 203121663Sharti if (size == 0) { 204121663Sharti got = 0; 205121663Sharti break; 206121663Sharti } 207121663Sharti got += (size_t)size; 208121663Sharti } 209121663Sharti 210121663Sharti } else { 211121663Sharti if ((m = uni_msg_alloc(MAXMSG)) == NULL) 212121663Sharti err(1, NULL); 213121663Sharti if ((size = read(user_fd, m->b_rptr, MAXMSG)) == -1) 214121663Sharti err(1, "error reading message"); 215121663Sharti got = size; 216121663Sharti } 217121663Sharti 218121663Sharti if (size == 0) { 219121663Sharti eof: 220135923Strhodes#ifdef USE_LIBBEGEMOT 221135923Strhodes poll_unregister(user_h); 222135923Strhodes#else 223121663Sharti evDeselectFD(evctx, user_h); 224135923Strhodes#endif 225121663Sharti if (m != NULL) 226121663Sharti uni_msg_destroy(m); 227121663Sharti VERBOSE(("EOF on user connection")); 228121663Sharti return (NULL); 229121663Sharti } 230121663Sharti m->b_wptr = m->b_rptr + size; 231121663Sharti 232121663Sharti return (m); 233121663Sharti} 234121663Sharti 235121663Sharti/* 236121663Sharti * Write message to the SSCOP file descriptor. 237121663Sharti * Here we have a problem: we should have a means to check how much space 238121663Sharti * we have. If the pipe is full, we could declare the lower layer busy and 239121663Sharti * drop the message. However, how do we know, when a message will fit? 240121663Sharti * Selecting for WRITE doesn't help, because it will return even if a single 241121663Sharti * byte can be written. For this reason, we switch the file descriptor to 242121663Sharti * blocking mode, and hope everything is fast enough to not timeout us. 243121663Sharti * Alternatively we could just drop the message. Using kevent would help here. 244121663Sharti */ 245121663Shartivoid 246121663Shartiproto_msgout(struct uni_msg *m) 247121663Sharti{ 248121663Sharti struct iovec iov[2]; 249121663Sharti u_int32_t flen; 250121663Sharti ssize_t size; 251121663Sharti static int sent; 252121663Sharti int fl; 253121663Sharti 254121663Sharti if (verbose & 0x0002) 255121663Sharti dump_buf("send", m->b_rptr, uni_msg_len(m)); 256121663Sharti if (loose > 0 && (sent++ % loose) == loose - 1) { 257121663Sharti VERBOSE(("loosing message")); 258121663Sharti uni_msg_destroy(m); 259121663Sharti return; 260121663Sharti } 261121663Sharti 262121663Sharti flen = uni_msg_len(m); 263121663Sharti 264121663Sharti iov[0].iov_len = sscopframe ? 4 : 0; 265121663Sharti iov[0].iov_base = (caddr_t)&flen; 266121663Sharti iov[1].iov_len = uni_msg_len(m); 267121663Sharti iov[1].iov_base = m->b_rptr; 268121663Sharti 269121663Sharti if ((fl = fcntl(sscop_fd, F_GETFL, 0)) == -1) 270121663Sharti err(1, "cannot get flags for sscop fd"); 271121663Sharti fl &= ~O_NONBLOCK; 272121663Sharti if (fcntl(sscop_fd, F_SETFL, fl) == -1) 273121663Sharti err(1, "cannot set flags for sscop fd"); 274121663Sharti 275121663Sharti if ((size = writev(sscop_fd, iov, 2)) == -1) 276121663Sharti err(1, "write sscop"); 277121663Sharti if ((size_t)size != iov[0].iov_len + iov[1].iov_len) 278121663Sharti err(1, "short sscop write %zu %zu %zd", 279121663Sharti iov[0].iov_len, iov[1].iov_len, size); 280121663Sharti 281121663Sharti fl |= O_NONBLOCK; 282121663Sharti if (fcntl(sscop_fd, F_SETFL, fl) == -1) 283121663Sharti err(1, "cannot restore flags for sscop fd"); 284121663Sharti 285121663Sharti uni_msg_destroy(m); 286121663Sharti} 287121663Sharti 288121663Sharti/* 289121663Sharti * output a message to the user 290121663Sharti */ 291121663Shartivoid 292121663Shartiuser_msgout(struct uni_msg *m) 293121663Sharti{ 294121663Sharti struct iovec iov[2]; 295121663Sharti u_int32_t flen; 296121663Sharti ssize_t size; 297121663Sharti 298121663Sharti flen = uni_msg_len(m); 299121663Sharti 300121663Sharti iov[0].iov_len = useframe ? 4 : 0; 301121663Sharti iov[0].iov_base = (caddr_t)&flen; 302121663Sharti iov[1].iov_len = uni_msg_len(m); 303121663Sharti iov[1].iov_base = m->b_rptr; 304121663Sharti 305121663Sharti if ((size = writev(user_out_fd, iov, 2)) == -1) 306121663Sharti err(1, "write sscop"); 307121663Sharti if ((size_t)size != iov[0].iov_len + iov[1].iov_len) 308121663Sharti errx(1, "short sscop write"); 309121663Sharti 310121663Sharti uni_msg_destroy(m); 311121663Sharti} 312121663Sharti 313121663Shartivoid 314121663Shartiparse_param(struct sscop_param *param, u_int *pmask, int opt, char *arg) 315121663Sharti{ 316121663Sharti u_int val; 317121663Sharti char *end, *p; 318121663Sharti 319121663Sharti if(opt == 'b') { 320121663Sharti param->flags |= SSCOP_ROBUST; 321121663Sharti *pmask |= SSCOP_SET_ROBUST; 322121663Sharti return; 323121663Sharti } 324121663Sharti if(opt == 'x') { 325121663Sharti param->flags |= SSCOP_POLLREX; 326121663Sharti *pmask |= SSCOP_SET_POLLREX; 327121663Sharti return; 328121663Sharti } 329121663Sharti if(opt == 'W') { 330121663Sharti val = (u_int)strtoul(optarg, &end, 0); 331121663Sharti 332121663Sharti if(*end != '\0') 333121663Sharti errx(1, "bad number to -W '%s'", optarg); 334121663Sharti if(val >= (1 << 24) - 1) 335121663Sharti errx(1, "window too large: 0x%x", val); 336121663Sharti param->mr = val; 337121663Sharti *pmask |= SSCOP_SET_MR; 338121663Sharti return; 339121663Sharti } 340121663Sharti 341121663Sharti if((p = strchr(arg, '=')) == NULL) 342121663Sharti errx(1, "need '=' in argument to -%c", opt); 343121663Sharti *p++ = 0; 344121663Sharti if(*p == 0) 345121663Sharti errx(1, "argument to -%c %s empty", opt, arg); 346121663Sharti val = strtoul(p, &end, 0); 347121663Sharti if(*end != 0) 348121663Sharti errx(1, "bad number in -%c %s=%s", opt, arg, p); 349121663Sharti 350121663Sharti if(opt == 't') { 351121663Sharti if(strcmp(arg, "cc") == 0) { 352121663Sharti param->timer_cc = val; 353121663Sharti *pmask |= SSCOP_SET_TCC; 354121663Sharti } else if(strcmp(arg, "poll") == 0) { 355121663Sharti param->timer_poll = val; 356121663Sharti *pmask |= SSCOP_SET_TPOLL; 357121663Sharti } else if(strcmp(arg, "ka") == 0) { 358121663Sharti param->timer_keep_alive = val; 359121663Sharti *pmask |= SSCOP_SET_TKA; 360121663Sharti } else if(strcmp(arg, "nr") == 0) { 361121663Sharti param->timer_no_response = val; 362121663Sharti *pmask |= SSCOP_SET_TNR; 363121663Sharti } else if(strcmp(arg, "idle") == 0) { 364121663Sharti param->timer_idle = val; 365121663Sharti *pmask |= SSCOP_SET_TIDLE; 366121663Sharti } else 367121663Sharti errx(1, "bad timer name '%s'", arg); 368121663Sharti return; 369121663Sharti } 370121663Sharti 371121663Sharti if(opt == 'a') { 372121663Sharti if(strcmp(arg, "j") == 0) { 373121663Sharti param->maxj = val; 374121663Sharti *pmask |= SSCOP_SET_MAXJ; 375121663Sharti } else if(strcmp(arg, "k") == 0) { 376121663Sharti param->maxk = val; 377121663Sharti *pmask |= SSCOP_SET_MAXK; 378121663Sharti } else if(strcmp(arg, "cc") == 0) { 379121663Sharti param->maxcc = val; 380121663Sharti *pmask |= SSCOP_SET_MAXCC; 381121663Sharti } else if(strcmp(arg, "pd") == 0) { 382121663Sharti param->maxpd = val; 383121663Sharti *pmask |= SSCOP_SET_MAXPD; 384121663Sharti } else if(strcmp(arg, "stat") == 0) { 385121663Sharti param->maxstat = val; 386121663Sharti *pmask |= SSCOP_SET_MAXSTAT; 387121663Sharti } else 388121663Sharti errx(1, "bad parameter '%s'", arg); 389121663Sharti return; 390121663Sharti } 391121663Sharti 392121663Sharti verb("bad flag"); 393121663Sharti abort(); 394121663Sharti} 395121663Sharti 396135923Strhodes#ifdef USE_LIBBEGEMOT 397121663Shartistatic void 398135923Strhodestfunc(int tid __unused, void *uap) 399135923Strhodes#else 400135923Strhodesstatic void 401121663Shartitfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 402121663Sharti struct timespec inter __unused) 403135923Strhodes#endif 404121663Sharti{ 405121663Sharti struct timer *t = uap; 406121663Sharti 407121663Sharti t->func(t->sscop); 408121663Sharti free(t); 409121663Sharti} 410121663Sharti 411121663Sharti/* 412121663Sharti * Start a timer 413121663Sharti */ 414121663Shartivoid * 415121663Shartisscop_start_timer(struct sscop *sscop, void *arg __unused, u_int msec, 416121663Sharti void (*func)(void *)) 417121663Sharti{ 418121663Sharti struct timer *t; 419135923Strhodes#ifndef USE_LIBBEGEMOT 420121663Sharti struct timespec due; 421135923Strhodes#endif 422121663Sharti 423121663Sharti if ((t = malloc(sizeof(*t))) == NULL) 424121663Sharti err(1, NULL); 425121663Sharti t->sscop = sscop; 426121663Sharti t->func = func; 427121663Sharti 428135923Strhodes#ifdef USE_LIBBEGEMOT 429135923Strhodes if ((t->id = poll_start_timer(msec, 0, tfunc, t)) == -1) 430135923Strhodes err(1, "cannot start timer"); 431135923Strhodes#else 432121663Sharti due = evAddTime(evNowTime(), 433121663Sharti evConsTime((time_t)msec/1000, (long)(msec%1000)*1000)); 434121663Sharti 435121663Sharti if (evSetTimer(evctx, tfunc, t, due, evConsTime(0, 0), &t->id)) 436121663Sharti err(1, "cannot start timer"); 437135923Strhodes#endif 438121663Sharti 439121663Sharti return (t); 440121663Sharti} 441121663Sharti 442121663Sharti/* 443121663Sharti * Stop a timer 444121663Sharti */ 445121663Shartivoid 446121663Shartisscop_stop_timer(struct sscop *sscop __unused, void *arg __unused, void *tp) 447121663Sharti{ 448121663Sharti struct timer *t = tp; 449121663Sharti 450135923Strhodes#ifdef USE_LIBBEGEMOT 451135923Strhodes poll_stop_timer(t->id); 452135923Strhodes#else 453121663Sharti evClearTimer(evctx, t->id); 454135923Strhodes#endif 455121663Sharti free(t); 456121663Sharti} 457