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/sscop_main.c,v 1.5 2005/05/23 11:46:17 brandt_h Exp $ 30 */ 31 32#include <sys/types.h> 33#include <sys/socket.h> 34#include <sys/uio.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38#include <errno.h> 39#include <unistd.h> 40#include <time.h> 41#include <signal.h> 42#include <assert.h> 43#include <err.h> 44 45#include <netnatm/unimsg.h> 46#include <netnatm/saal/sscop.h> 47#include "common.h" 48 49static int sigusr1; /* got SIGUSR1 */ 50static int unidir; /* write only user */ 51static int end_at_eof = 1; /* send RELEASE_request at user EOF */ 52 53static volatile int ready; /* flag if connection is established */ 54static volatile int finished; /* got release confirm or indication */ 55 56static const char usgtxt[] = "\ 57SSCOP transport protocol\n\ 58Usage: sscop [-h] [-Fbefirwx3] [-ap=v] [-lN] [-tt=m] [-v X] [-V X] [-W N]\n\ 59Options:\n\ 60 -F use framing for sscop also\n\ 61 -V X set verbose flags to hex X\n\ 62 -W N set initial window to N\n\ 63 -a p=v set parameter 'p' to 'v'\n\ 64 -b enable robustness enhancement\n\ 65 -e don't RELEASE_request on user EOF\n\ 66 -f use begemot frame functions for user fd\n\ 67 -h print this info\n\ 68 -i use user fd only for output\n\ 69 -lN loose every nth message\n\ 70 -r reverse user and sscop file descriptors\n\ 71 -t t=m set timer 't' to 'm' milliseconds\n\ 72 -v X set sscop verbose flags to hex X\n\ 73 -w don't start conversation\n\ 74 -x enable POLL after retransmission\n\ 75 -3 redirect output to fd 3\n\ 76Timers are cc, poll, ka, nr or idle; parameters are j, k, cc, pd or stat.\n"; 77 78static void sscop_send_manage(struct sscop *, void *, 79 enum sscop_maasig, struct uni_msg *, u_int, u_int); 80static void sscop_send_upper(struct sscop *, void *, enum sscop_aasig, 81 struct SSCOP_MBUF_T *, u_int); 82static void sscop_send_lower(struct sscop *, void *, struct SSCOP_MBUF_T *); 83 84static const struct sscop_funcs sscop_funcs = { 85 sscop_send_manage, 86 sscop_send_upper, 87 sscop_send_lower, 88 sscop_verbose, 89 sscop_start_timer, 90 sscop_stop_timer 91}; 92 93/* 94 * SSCOP file descriptor is ready. Allocate and read one message 95 * and dispatch a signal. 96 */ 97#ifdef USE_LIBBEGEMOT 98static void 99proto_infunc(int fd, int mask __unused, void *uap) 100#else 101static void 102proto_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused) 103#endif 104{ 105 struct uni_msg *m; 106 107 if ((m = proto_msgin(fd)) != NULL) 108 sscop_input((struct sscop *)uap, m); 109} 110 111/* 112 * User input. Allocate and read message and dispatch signal. 113 */ 114#ifdef USE_LIBBEGEMOT 115static void 116user_infunc(int fd, int mask __unused, void *uap) 117#else 118static void 119user_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused) 120#endif 121{ 122 struct uni_msg *m; 123 124 if ((m = user_msgin(fd)) != NULL) 125 sscop_aasig((struct sscop *)uap, SSCOP_DATA_request, m, 0); 126 127 else if (end_at_eof) 128 sscop_aasig((struct sscop *)uap, SSCOP_RELEASE_request, 0, 0); 129} 130 131static void 132onusr1(int s __unused) 133{ 134 sigusr1++; 135} 136 137int 138main(int argc, char *argv[]) 139{ 140 int opt; 141 struct sscop *sscop; 142 struct sscop_param param; 143 struct sigaction sa; 144 int wait = 0; 145 u_int mask; 146#ifndef USE_LIBBEGEMOT 147 evEvent ev; 148#endif 149 150 /* 151 * Default is to have the USER on stdin and SSCOP on stdout 152 */ 153 sscop_fd = 0; 154 user_fd = 1; 155 user_out_fd = -1; 156 157 memset(¶m, 0, sizeof(param)); 158 param.maxk = MAXUSRMSG; 159 param.maxj = 0; 160 param.maxcc = 4; 161 mask = SSCOP_SET_MAXK | SSCOP_SET_MAXJ | SSCOP_SET_MAXCC; 162 163 while((opt = getopt(argc, argv, "3a:befFhil:rt:v:V:wW:x")) != -1) 164 switch(opt) { 165 166 case '3': 167 user_out_fd = 3; 168 break; 169 170 case 'e': 171 end_at_eof = 0; 172 break; 173 174 case 'f': 175 useframe = 1; 176 break; 177 178 case 'F': 179 sscopframe = 1; 180 break; 181 182 case 'h': 183 fprintf(stderr, usgtxt); 184 exit(0); 185 186 case 'i': 187 unidir++; 188 break; 189 190 case 'l': 191 loose = strtoul(optarg, NULL, 0); 192 break; 193 194 case 'r': 195 sscop_fd = 1; 196 user_fd = 0; 197 break; 198 199 case 'v': 200 sscop_vflag = strtoul(optarg, NULL, 16); 201 break; 202 203 case 'V': 204 verbose = strtoul(optarg, NULL, 16); 205 break; 206 207 case 'w': 208 wait = 1; 209 break; 210 211 case 'a': 212 case 't': 213 case 'b': 214 case 'x': 215 case 'W': 216 parse_param(¶m, &mask, opt, optarg); 217 break; 218 } 219 220 if(user_out_fd < 0) 221 user_out_fd = user_fd; 222 223#ifndef USE_LIBBEGEMOT 224 if (evCreate(&evctx)) 225 err(1, "evCreate"); 226#endif 227 228 /* 229 * Catch USR1 230 */ 231 sa.sa_handler = onusr1; 232 sigemptyset(&sa.sa_mask); 233 sa.sa_flags = SA_RESTART; 234 if(sigaction(SIGUSR1, &sa, NULL)) 235 err(1, "sigaction(SIGUSR1)"); 236 237 /* 238 * Allocate and initialize SSCOP 239 */ 240 if ((sscop = sscop_create(NULL, &sscop_funcs)) == NULL) 241 err(1, NULL); 242 sscop_setdebug(sscop, sscop_vflag); 243 if ((errno = sscop_setparam(sscop, ¶m, &mask)) != 0) 244 err(1, "can't set sscop parameters %#x", mask); 245 246 /* 247 * Register sscop fd 248 */ 249#ifdef USE_LIBBEGEMOT 250 if ((sscop_h = poll_register(sscop_fd, proto_infunc, 251 sscop, POLL_IN)) == -1) 252 err(1, "can't select on sscop fd"); 253#else 254 if (evSelectFD(evctx, sscop_fd, EV_READ, proto_infunc, sscop, &sscop_h)) 255 err(1, "can't select on sscop fd"); 256#endif 257 258 /* 259 * if we are active - send establish request 260 */ 261 if(!wait) 262 sscop_aasig(sscop, SSCOP_ESTABLISH_request, NULL, 1); 263 264 /* 265 * Run protocol until it get's ready 266 */ 267 while (sscop_fd >= 0 && !ready) { 268#ifdef USE_LIBBEGEMOT 269 poll_dispatch(1); 270#else 271 if (evGetNext(evctx, &ev, EV_WAIT) == 0) { 272 if (evDispatch(evctx, ev)) 273 err(1, "dispatch event"); 274 } else if (errno != EINTR) 275 err(1, "get event"); 276#endif 277 } 278 279 /* 280 * If this led to a closed file - exit. 281 */ 282 if (sscop_fd < 0) { 283 VERBOSE(("SSCOP file descriptor closed - exiting")); 284 sscop_destroy(sscop); 285 return 0; 286 } 287 288 VERBOSE(("READY - starting data transfer")); 289 290 if (!unidir && 291#ifdef USE_LIBBEGEMOT 292 ((user_h = poll_register(user_fd, user_infunc, sscop, POLL_IN)) == -1)) 293#else 294 evSelectFD(evctx, user_fd, EV_READ, user_infunc, sscop, &user_h)) 295#endif 296 err(1, "can't select on sscop fd"); 297 298 while (!sigusr1 && sscop_fd >= 0) { 299#ifdef USE_LIBBEGEMOT 300 poll_dispatch(1); 301#else 302 if (evGetNext(evctx, &ev, EV_WAIT) == 0) { 303 if (evDispatch(evctx, ev)) 304 err(1, "dispatch event"); 305 } else if (errno != EINTR) 306 err(1, "get event"); 307#endif 308 } 309 310 if (sigusr1 && sscop_fd >= 0) { 311 /* 312 * Release if we still have the connection 313 */ 314 sscop_aasig(sscop, SSCOP_RELEASE_request, NULL, 0); 315 while (!finished && sscop_fd >= 0) { 316#ifdef USE_LIBBEGEMOT 317 poll_dispatch(1); 318#else 319 if (evGetNext(evctx, &ev, EV_WAIT) == 0) { 320 if (evDispatch(evctx, ev)) 321 err(1, "dispatch event"); 322 } else if (errno != EINTR) 323 err(1, "get event"); 324#endif 325 } 326 } 327 328 VERBOSE(("SSCOP file descriptor closed - exiting")); 329 sscop_destroy(sscop); 330 331 return (0); 332} 333 334 335 336/* 337 * AAL OUTPUT 338 */ 339static void 340sscop_send_lower(struct sscop *sscop __unused, void *arg __unused, 341 struct SSCOP_MBUF_T *m) 342{ 343 proto_msgout(m); 344} 345 346 347/* 348 * Write the message to the user and move the window 349 */ 350static void 351uoutput(struct sscop *sscop, struct uni_msg *m) 352{ 353 user_msgout(m); 354 sscop_window(sscop, +1); 355} 356 357/* 358 * SSCOP AA-SIGNALS 359 */ 360static void 361sscop_send_upper(struct sscop *sscop, void *arg __unused, enum sscop_aasig sig, 362 struct SSCOP_MBUF_T *m, u_int p __unused) 363{ 364 VERBOSE(("--> got aa %d(%s)", sig, sscop_signame(sig))); 365 366 switch (sig) { 367 368 case SSCOP_RELEASE_indication: 369 if (end_at_eof) { 370 VERBOSE((" ... exiting")); 371#ifdef USE_LIBBEGEMOT 372 poll_unregister(sscop_h); 373#else 374 evDeselectFD(evctx, sscop_h); 375#endif 376 (void)close(sscop_fd); 377 sscop_fd = -1; 378 } 379 finished++; 380 if (m) 381 uni_msg_destroy(m); 382 break; 383 384 case SSCOP_RELEASE_confirm: 385 if (end_at_eof) { 386 VERBOSE((" ... exiting")); 387#ifdef USE_LIBBEGEMOT 388 poll_unregister(sscop_h); 389#else 390 evDeselectFD(evctx, sscop_h); 391#endif 392 (void)close(sscop_fd); 393 sscop_fd = -1; 394 } 395 finished++; 396 break; 397 398 case SSCOP_ESTABLISH_indication: 399 sscop_aasig(sscop, SSCOP_ESTABLISH_response, NULL, 1); 400 ready++; 401 if (m) 402 uni_msg_destroy(m); 403 break; 404 405 case SSCOP_ESTABLISH_confirm: 406 ready++; 407 if (m) 408 uni_msg_destroy(m); 409 break; 410 411 case SSCOP_DATA_indication: 412 assert(m != NULL); 413 uoutput(sscop, m); 414 break; 415 416 case SSCOP_UDATA_indication: 417 assert(m != NULL); 418 VERBOSE(("UDATA.indication ignored")); 419 uni_msg_destroy(m); 420 break; 421 422 case SSCOP_RECOVER_indication: 423 sscop_aasig(sscop, SSCOP_RECOVER_response, NULL, 0); 424 break; 425 426 case SSCOP_RESYNC_indication: 427 sscop_aasig(sscop, SSCOP_RESYNC_response, NULL, 0); 428 if (m) 429 uni_msg_destroy(m); 430 break; 431 432 case SSCOP_RESYNC_confirm: 433 break; 434 435 case SSCOP_RETRIEVE_indication: 436 case SSCOP_RETRIEVE_COMPL_indication: 437 warnx("Ooops. A retrieve indication"); 438 abort(); 439 440 case SSCOP_ESTABLISH_request: 441 case SSCOP_RELEASE_request: 442 case SSCOP_ESTABLISH_response: 443 case SSCOP_DATA_request: 444 case SSCOP_UDATA_request: 445 case SSCOP_RECOVER_response: 446 case SSCOP_RESYNC_request: 447 case SSCOP_RESYNC_response: 448 case SSCOP_RETRIEVE_request: 449 warnx("bad signal for this direction"); 450 abort(); 451 } 452} 453 454/* 455 * This get's called for MAAL 456 */ 457static void 458sscop_send_manage(struct sscop *sscop __unused, void *arg __unused, 459 enum sscop_maasig sig, struct uni_msg *m, u_int error, u_int cnt) 460{ 461 VERBOSE(("--> got maa %d(%s)", sig, sscop_msigname(sig))); 462 463 switch (sig) { 464 465 case SSCOP_MDATA_indication: 466 VERBOSE(("MDATA.indication ignored")); 467 uni_msg_destroy(m); 468 break; 469 470 case SSCOP_MERROR_indication: 471 VERBOSE(("MAAL-ERROR.indication '%c' %u", error, cnt)); 472 break; 473 474 case SSCOP_MDATA_request: 475 warnx("bad signal for this direction"); 476 abort(); 477 } 478} 479