1/* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Begemot: libunimsg/sscop/common.c,v 1.5 2005/05/23 11:46:16 brandt_h Exp $ 30 */ 31 32#include <sys/types.h> 33#include <sys/socket.h> 34#include <sys/uio.h> 35 36#include <stdio.h> 37#include <stdlib.h> 38#include <stdarg.h> 39#include <string.h> 40#include <errno.h> 41#include <unistd.h> 42#include <time.h> 43#include <signal.h> 44#include <assert.h> 45#include <fcntl.h> 46#include <err.h> 47 48#include <netnatm/unimsg.h> 49#include <netnatm/saal/sscop.h> 50#include "common.h" 51 52struct timer { 53 evTimerID id; 54 struct sscop *sscop; 55 void (*func)(void *); 56}; 57 58int useframe; 59int sscopframe; 60u_int sscop_vflag; 61int sscop_fd; 62int user_fd; 63int loose; 64int user_out_fd; 65u_int verbose; 66#ifndef USE_LIBBEGEMOT 67evContext evctx; 68#endif 69evFileID sscop_h; 70evFileID user_h; 71 72/* 73 * This function get's called from sscop to put out verbose messages 74 */ 75void 76sscop_verbose(struct sscop *sscop __unused, void *u __unused, 77 const char *fmt, ...) 78{ 79 va_list ap; 80 81 va_start(ap, fmt); 82 vfprintf(stderr, fmt, ap); 83 fprintf(stderr, "\n"); 84 va_end(ap); 85} 86void 87verb(const char *fmt, ...) 88{ 89 va_list ap; 90 91 va_start(ap, fmt); 92 vfprintf(stderr, fmt, ap); 93 fprintf(stderr, "\n"); 94 va_end(ap); 95} 96 97/* 98 * Dump a buffer in hex to stderr. 99 */ 100void 101dump_buf(const char *w, const u_char *buf, size_t len) 102{ 103 u_int i; 104 105 fprintf(stderr, "%s %zu: ", w, len); 106 for(i = 0; i < len; i++) { 107 if (i % 4 == 0 && i != 0) 108 fprintf(stderr, " "); 109 fprintf(stderr, "%02x", *buf++); 110 } 111 fprintf(stderr, "\n"); 112} 113 114/* 115 * SSCOP file descriptor is ready. Allocate and read one message 116 * and dispatch a signal. 117 */ 118struct uni_msg * 119proto_msgin(int fd __unused) 120{ 121 struct uni_msg *m = NULL; 122 ssize_t size; 123 u_int32_t flen; 124 u_int got; 125 126 if (sscopframe) { 127 if ((size = read(sscop_fd, &flen, 4)) == -1) 128 err(1, "error reading frame hdr"); 129 if (size == 0) { 130 got = 0; 131 goto eof; 132 } 133 if (size != 4) 134 errx(1, "short frame header: %zd", size); 135 if ((m = uni_msg_alloc(flen)) == NULL) 136 err(1, NULL); 137 for (got = 0; got < flen; got += (size_t)size) { 138 size = read(sscop_fd, m->b_rptr + got, flen - got); 139 if (size == -1) 140 err(1, "error reading frame"); 141 if (size == 0) { 142 got = 0; 143 break; 144 } 145 } 146 147 } else { 148 if ((m = uni_msg_alloc(MAXMSG)) == NULL) 149 err(1, NULL); 150 if ((size = read(sscop_fd, m->b_rptr, MAXMSG)) == -1) 151 err(1, "error reading message"); 152 got = size; 153 } 154 155 if (got == 0) { 156 eof: 157#ifdef USE_LIBBEGEMOT 158 poll_unregister(sscop_h); 159#else 160 evDeselectFD(evctx, sscop_h); 161#endif 162 (void)close(sscop_fd); 163 sscop_fd = -1; 164 if (m != NULL) 165 uni_msg_destroy(m); 166 VERBOSE(("EOF on sscop file descriptor")); 167 return (NULL); 168 } 169 m->b_wptr = m->b_rptr + got; 170 171 if(verbose & 0x0002) 172 dump_buf("SSCOP INPUT", m->b_rptr, got); 173 174 return (m); 175} 176 177/* 178 * User file descriptor ready - read a message 179 */ 180struct uni_msg * 181user_msgin(int fd __unused) 182{ 183 struct uni_msg *m = NULL; 184 ssize_t size; 185 u_int32_t flen; 186 u_int got; 187 188 if (useframe) { 189 if ((size = read(user_fd, &flen, 4)) == -1) 190 err(1, "error reading frame hdr"); 191 if (size == 0) { 192 got = 0; 193 goto eof; 194 } 195 if (size != 4) 196 errx(1, "short frame header: %zd", size); 197 if ((m = uni_msg_alloc(flen)) == NULL) 198 err(1, NULL); 199 for (got = 0; got < flen; got++) { 200 size = read(user_fd, m->b_rptr + got, flen - got); 201 if (size == -1) 202 err(1, "error reading frame"); 203 if (size == 0) { 204 got = 0; 205 break; 206 } 207 got += (size_t)size; 208 } 209 210 } else { 211 if ((m = uni_msg_alloc(MAXMSG)) == NULL) 212 err(1, NULL); 213 if ((size = read(user_fd, m->b_rptr, MAXMSG)) == -1) 214 err(1, "error reading message"); 215 got = size; 216 } 217 218 if (size == 0) { 219 eof: 220#ifdef USE_LIBBEGEMOT 221 poll_unregister(user_h); 222#else 223 evDeselectFD(evctx, user_h); 224#endif 225 if (m != NULL) 226 uni_msg_destroy(m); 227 VERBOSE(("EOF on user connection")); 228 return (NULL); 229 } 230 m->b_wptr = m->b_rptr + size; 231 232 return (m); 233} 234 235/* 236 * Write message to the SSCOP file descriptor. 237 * Here we have a problem: we should have a means to check how much space 238 * we have. If the pipe is full, we could declare the lower layer busy and 239 * drop the message. However, how do we know, when a message will fit? 240 * Selecting for WRITE doesn't help, because it will return even if a single 241 * byte can be written. For this reason, we switch the file descriptor to 242 * blocking mode, and hope everything is fast enough to not timeout us. 243 * Alternatively we could just drop the message. Using kevent would help here. 244 */ 245void 246proto_msgout(struct uni_msg *m) 247{ 248 struct iovec iov[2]; 249 u_int32_t flen; 250 ssize_t size; 251 static int sent; 252 int fl; 253 254 if (verbose & 0x0002) 255 dump_buf("send", m->b_rptr, uni_msg_len(m)); 256 if (loose > 0 && (sent++ % loose) == loose - 1) { 257 VERBOSE(("loosing message")); 258 uni_msg_destroy(m); 259 return; 260 } 261 262 flen = uni_msg_len(m); 263 264 iov[0].iov_len = sscopframe ? 4 : 0; 265 iov[0].iov_base = (caddr_t)&flen; 266 iov[1].iov_len = uni_msg_len(m); 267 iov[1].iov_base = m->b_rptr; 268 269 if ((fl = fcntl(sscop_fd, F_GETFL, 0)) == -1) 270 err(1, "cannot get flags for sscop fd"); 271 fl &= ~O_NONBLOCK; 272 if (fcntl(sscop_fd, F_SETFL, fl) == -1) 273 err(1, "cannot set flags for sscop fd"); 274 275 if ((size = writev(sscop_fd, iov, 2)) == -1) 276 err(1, "write sscop"); 277 if ((size_t)size != iov[0].iov_len + iov[1].iov_len) 278 err(1, "short sscop write %zu %zu %zd", 279 iov[0].iov_len, iov[1].iov_len, size); 280 281 fl |= O_NONBLOCK; 282 if (fcntl(sscop_fd, F_SETFL, fl) == -1) 283 err(1, "cannot restore flags for sscop fd"); 284 285 uni_msg_destroy(m); 286} 287 288/* 289 * output a message to the user 290 */ 291void 292user_msgout(struct uni_msg *m) 293{ 294 struct iovec iov[2]; 295 u_int32_t flen; 296 ssize_t size; 297 298 flen = uni_msg_len(m); 299 300 iov[0].iov_len = useframe ? 4 : 0; 301 iov[0].iov_base = (caddr_t)&flen; 302 iov[1].iov_len = uni_msg_len(m); 303 iov[1].iov_base = m->b_rptr; 304 305 if ((size = writev(user_out_fd, iov, 2)) == -1) 306 err(1, "write sscop"); 307 if ((size_t)size != iov[0].iov_len + iov[1].iov_len) 308 errx(1, "short sscop write"); 309 310 uni_msg_destroy(m); 311} 312 313void 314parse_param(struct sscop_param *param, u_int *pmask, int opt, char *arg) 315{ 316 u_int val; 317 char *end, *p; 318 319 if(opt == 'b') { 320 param->flags |= SSCOP_ROBUST; 321 *pmask |= SSCOP_SET_ROBUST; 322 return; 323 } 324 if(opt == 'x') { 325 param->flags |= SSCOP_POLLREX; 326 *pmask |= SSCOP_SET_POLLREX; 327 return; 328 } 329 if(opt == 'W') { 330 val = (u_int)strtoul(optarg, &end, 0); 331 332 if(*end != '\0') 333 errx(1, "bad number to -W '%s'", optarg); 334 if(val >= (1 << 24) - 1) 335 errx(1, "window too large: 0x%x", val); 336 param->mr = val; 337 *pmask |= SSCOP_SET_MR; 338 return; 339 } 340 341 if((p = strchr(arg, '=')) == NULL) 342 errx(1, "need '=' in argument to -%c", opt); 343 *p++ = 0; 344 if(*p == 0) 345 errx(1, "argument to -%c %s empty", opt, arg); 346 val = strtoul(p, &end, 0); 347 if(*end != 0) 348 errx(1, "bad number in -%c %s=%s", opt, arg, p); 349 350 if(opt == 't') { 351 if(strcmp(arg, "cc") == 0) { 352 param->timer_cc = val; 353 *pmask |= SSCOP_SET_TCC; 354 } else if(strcmp(arg, "poll") == 0) { 355 param->timer_poll = val; 356 *pmask |= SSCOP_SET_TPOLL; 357 } else if(strcmp(arg, "ka") == 0) { 358 param->timer_keep_alive = val; 359 *pmask |= SSCOP_SET_TKA; 360 } else if(strcmp(arg, "nr") == 0) { 361 param->timer_no_response = val; 362 *pmask |= SSCOP_SET_TNR; 363 } else if(strcmp(arg, "idle") == 0) { 364 param->timer_idle = val; 365 *pmask |= SSCOP_SET_TIDLE; 366 } else 367 errx(1, "bad timer name '%s'", arg); 368 return; 369 } 370 371 if(opt == 'a') { 372 if(strcmp(arg, "j") == 0) { 373 param->maxj = val; 374 *pmask |= SSCOP_SET_MAXJ; 375 } else if(strcmp(arg, "k") == 0) { 376 param->maxk = val; 377 *pmask |= SSCOP_SET_MAXK; 378 } else if(strcmp(arg, "cc") == 0) { 379 param->maxcc = val; 380 *pmask |= SSCOP_SET_MAXCC; 381 } else if(strcmp(arg, "pd") == 0) { 382 param->maxpd = val; 383 *pmask |= SSCOP_SET_MAXPD; 384 } else if(strcmp(arg, "stat") == 0) { 385 param->maxstat = val; 386 *pmask |= SSCOP_SET_MAXSTAT; 387 } else 388 errx(1, "bad parameter '%s'", arg); 389 return; 390 } 391 392 verb("bad flag"); 393 abort(); 394} 395 396#ifdef USE_LIBBEGEMOT 397static void 398tfunc(int tid __unused, void *uap) 399#else 400static void 401tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 402 struct timespec inter __unused) 403#endif 404{ 405 struct timer *t = uap; 406 407 t->func(t->sscop); 408 free(t); 409} 410 411/* 412 * Start a timer 413 */ 414void * 415sscop_start_timer(struct sscop *sscop, void *arg __unused, u_int msec, 416 void (*func)(void *)) 417{ 418 struct timer *t; 419#ifndef USE_LIBBEGEMOT 420 struct timespec due; 421#endif 422 423 if ((t = malloc(sizeof(*t))) == NULL) 424 err(1, NULL); 425 t->sscop = sscop; 426 t->func = func; 427 428#ifdef USE_LIBBEGEMOT 429 if ((t->id = poll_start_timer(msec, 0, tfunc, t)) == -1) 430 err(1, "cannot start timer"); 431#else 432 due = evAddTime(evNowTime(), 433 evConsTime((time_t)msec/1000, (long)(msec%1000)*1000)); 434 435 if (evSetTimer(evctx, tfunc, t, due, evConsTime(0, 0), &t->id)) 436 err(1, "cannot start timer"); 437#endif 438 439 return (t); 440} 441 442/* 443 * Stop a timer 444 */ 445void 446sscop_stop_timer(struct sscop *sscop __unused, void *arg __unused, void *tp) 447{ 448 struct timer *t = tp; 449 450#ifdef USE_LIBBEGEMOT 451 poll_stop_timer(t->id); 452#else 453 evClearTimer(evctx, t->id); 454#endif 455 free(t); 456} 457