sscop_main.c revision 121663
1/* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * Author: Harti Brandt <harti@freebsd.org> 28 * 29 * $Begemot: libunimsg/sscop/sscop_main.c,v 1.3 2003/09/19 13:10:35 hbb 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#include <isc/eventlib.h> 45 46#include <netnatm/unimsg.h> 47#include <netnatm/saal/sscop.h> 48#include "common.h" 49 50static int sigusr1; /* got SIGUSR1 */ 51static int unidir; /* write only user */ 52static int end_at_eof = 1; /* send RELEASE_request at user EOF */ 53 54static volatile int ready; /* flag if connection is established */ 55static volatile int finished; /* got release confirm or indication */ 56 57static const char usgtxt[] = "\ 58SSCOP transport protocol\n\ 59Usage: sscop [-h] [-Fbefirwx3] [-ap=v] [-lN] [-tt=m] [-v X] [-V X] [-W N]\n\ 60Options:\n\ 61 -F use framing for sscop also\n\ 62 -V X set verbose flags to hex X\n\ 63 -W N set initial window to N\n\ 64 -a p=v set parameter 'p' to 'v'\n\ 65 -b enable robustness enhancement\n\ 66 -e don't RELEASE_request on user EOF\n\ 67 -f use begemot frame functions for user fd\n\ 68 -h print this info\n\ 69 -i use user fd only for output\n\ 70 -lN loose every nth message\n\ 71 -r reverse user and sscop file descriptors\n\ 72 -t t=m set timer 't' to 'm' milliseconds\n\ 73 -v X set sscop verbose flags to hex X\n\ 74 -w don't start conversation\n\ 75 -x enable POLL after retransmission\n\ 76 -3 redirect output to fd 3\n\ 77Timers are cc, poll, ka, nr or idle; parameters are j, k, cc, pd or stat.\n"; 78 79static void sscop_send_manage(struct sscop *, void *, 80 enum sscop_maasig, struct uni_msg *, u_int, u_int); 81static void sscop_send_upper(struct sscop *, void *, enum sscop_aasig, 82 struct SSCOP_MBUF_T *, u_int); 83static void sscop_send_lower(struct sscop *, void *, struct SSCOP_MBUF_T *); 84 85static const struct sscop_funcs sscop_funcs = { 86 sscop_send_manage, 87 sscop_send_upper, 88 sscop_send_lower, 89 sscop_verbose, 90 sscop_start_timer, 91 sscop_stop_timer 92}; 93 94/* 95 * SSCOP file descriptor is ready. Allocate and read one message 96 * and dispatch a signal. 97 */ 98static void 99proto_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused) 100{ 101 struct uni_msg *m; 102 103 if ((m = proto_msgin(fd)) != NULL) 104 sscop_input((struct sscop *)uap, m); 105} 106 107/* 108 * User input. Allocate and read message and dispatch signal. 109 */ 110static void 111user_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused) 112{ 113 struct uni_msg *m; 114 115 if ((m = user_msgin(fd)) != NULL) 116 sscop_aasig((struct sscop *)uap, SSCOP_DATA_request, m, 0); 117 118 else if (end_at_eof) 119 sscop_aasig((struct sscop *)uap, SSCOP_RELEASE_request, 0, 0); 120} 121 122static void 123onusr1(int s __unused) 124{ 125 sigusr1++; 126} 127 128int 129main(int argc, char *argv[]) 130{ 131 int opt; 132 struct sscop *sscop; 133 struct sscop_param param; 134 struct sigaction sa; 135 int wait = 0; 136 u_int mask; 137 evEvent ev; 138 139 /* 140 * Default is to have the USER on stdin and SSCOP on stdout 141 */ 142 sscop_fd = 0; 143 user_fd = 1; 144 user_out_fd = -1; 145 146 memset(¶m, 0, sizeof(param)); 147 param.maxk = MAXUSRMSG; 148 param.maxj = 0; 149 param.maxcc = 4; 150 mask = SSCOP_SET_MAXK | SSCOP_SET_MAXJ | SSCOP_SET_MAXCC; 151 152 while((opt = getopt(argc, argv, "3a:befFhil:rt:v:V:wW:x")) != -1) 153 switch(opt) { 154 155 case '3': 156 user_out_fd = 3; 157 break; 158 159 case 'e': 160 end_at_eof = 0; 161 break; 162 163 case 'f': 164 useframe = 1; 165 break; 166 167 case 'F': 168 sscopframe = 1; 169 break; 170 171 case 'h': 172 fprintf(stderr, usgtxt); 173 exit(0); 174 175 case 'i': 176 unidir++; 177 break; 178 179 case 'l': 180 loose = strtoul(optarg, NULL, 0); 181 break; 182 183 case 'r': 184 sscop_fd = 1; 185 user_fd = 0; 186 break; 187 188 case 'v': 189 sscop_vflag = strtoul(optarg, NULL, 16); 190 break; 191 192 case 'V': 193 verbose = strtoul(optarg, NULL, 16); 194 break; 195 196 case 'w': 197 wait = 1; 198 break; 199 200 case 'a': 201 case 't': 202 case 'b': 203 case 'x': 204 case 'W': 205 parse_param(¶m, &mask, opt, optarg); 206 break; 207 } 208 209 if(user_out_fd < 0) 210 user_out_fd = user_fd; 211 212 if (evCreate(&evctx)) 213 err(1, "evCreate"); 214 215 /* 216 * Catch USR1 217 */ 218 sa.sa_handler = onusr1; 219 sigemptyset(&sa.sa_mask); 220 sa.sa_flags = SA_RESTART; 221 if(sigaction(SIGUSR1, &sa, NULL)) 222 err(1, "sigaction(SIGUSR1)"); 223 224 /* 225 * Allocate and initialize SSCOP 226 */ 227 if ((sscop = sscop_create(NULL, &sscop_funcs)) == NULL) 228 err(1, NULL); 229 sscop_setdebug(sscop, sscop_vflag); 230 if ((errno = sscop_setparam(sscop, ¶m, &mask)) != 0) 231 err(1, "can't set sscop parameters %#x", mask); 232 233 /* 234 * Register sscop fd 235 */ 236 if (evSelectFD(evctx, sscop_fd, EV_READ, proto_infunc, sscop, &sscop_h)) 237 err(1, "can't select on sscop fd"); 238 239 /* 240 * if we are active - send establish request 241 */ 242 if(!wait) 243 sscop_aasig(sscop, SSCOP_ESTABLISH_request, NULL, 1); 244 245 /* 246 * Run protocol until it get's ready 247 */ 248 while (sscop_fd >= 0 && !ready) { 249 if (evGetNext(evctx, &ev, EV_WAIT) == 0) { 250 if (evDispatch(evctx, ev)) 251 err(1, "dispatch event"); 252 } else if (errno != EINTR) 253 err(1, "get event"); 254 } 255 256 /* 257 * If this led to a closed file - exit. 258 */ 259 if (sscop_fd < 0) { 260 VERBOSE(("SSCOP file descriptor closed - exiting")); 261 sscop_destroy(sscop); 262 return 0; 263 } 264 265 VERBOSE(("READY - starting data transfer")); 266 267 if (!unidir && 268 evSelectFD(evctx, user_fd, EV_READ, user_infunc, sscop, &user_h)) 269 err(1, "can't select on sscop fd"); 270 271 while (!sigusr1 && sscop_fd >= 0) { 272 if (evGetNext(evctx, &ev, EV_WAIT) == 0) { 273 if (evDispatch(evctx, ev)) 274 err(1, "dispatch event"); 275 } else if (errno != EINTR) 276 err(1, "get event"); 277 } 278 279 if (sigusr1 && sscop_fd >= 0) { 280 /* 281 * Release if we still have the connection 282 */ 283 sscop_aasig(sscop, SSCOP_RELEASE_request, NULL, 0); 284 while (!finished && sscop_fd >= 0) { 285 if (evGetNext(evctx, &ev, EV_WAIT) == 0) { 286 if (evDispatch(evctx, ev)) 287 err(1, "dispatch event"); 288 } else if (errno != EINTR) 289 err(1, "get event"); 290 } 291 } 292 293 VERBOSE(("SSCOP file descriptor closed - exiting")); 294 sscop_destroy(sscop); 295 296 return (0); 297} 298 299 300 301/* 302 * AAL OUTPUT 303 */ 304static void 305sscop_send_lower(struct sscop *sscop __unused, void *arg __unused, 306 struct SSCOP_MBUF_T *m) 307{ 308 proto_msgout(m); 309} 310 311 312/* 313 * Write the message to the user and move the window 314 */ 315static void 316uoutput(struct sscop *sscop, struct uni_msg *m) 317{ 318 user_msgout(m); 319 sscop_window(sscop, +1); 320} 321 322/* 323 * SSCOP AA-SIGNALS 324 */ 325static void 326sscop_send_upper(struct sscop *sscop, void *arg __unused, enum sscop_aasig sig, 327 struct SSCOP_MBUF_T *m, u_int p __unused) 328{ 329 VERBOSE(("--> got aa %d(%s)", sig, sscop_signame(sig))); 330 331 switch (sig) { 332 333 case SSCOP_RELEASE_indication: 334 if (end_at_eof) { 335 VERBOSE((" ... exiting")); 336 evDeselectFD(evctx, sscop_h); 337 (void)close(sscop_fd); 338 sscop_fd = -1; 339 } 340 finished++; 341 if (m) 342 uni_msg_destroy(m); 343 break; 344 345 case SSCOP_RELEASE_confirm: 346 if (end_at_eof) { 347 VERBOSE((" ... exiting")); 348 evDeselectFD(evctx, sscop_h); 349 (void)close(sscop_fd); 350 sscop_fd = -1; 351 } 352 finished++; 353 break; 354 355 case SSCOP_ESTABLISH_indication: 356 sscop_aasig(sscop, SSCOP_ESTABLISH_response, NULL, 1); 357 ready++; 358 if (m) 359 uni_msg_destroy(m); 360 break; 361 362 case SSCOP_ESTABLISH_confirm: 363 ready++; 364 if (m) 365 uni_msg_destroy(m); 366 break; 367 368 case SSCOP_DATA_indication: 369 assert(m != NULL); 370 uoutput(sscop, m); 371 break; 372 373 case SSCOP_UDATA_indication: 374 assert(m != NULL); 375 VERBOSE(("UDATA.indication ignored")); 376 uni_msg_destroy(m); 377 break; 378 379 case SSCOP_RECOVER_indication: 380 sscop_aasig(sscop, SSCOP_RECOVER_response, NULL, 0); 381 break; 382 383 case SSCOP_RESYNC_indication: 384 sscop_aasig(sscop, SSCOP_RESYNC_response, NULL, 0); 385 if (m) 386 uni_msg_destroy(m); 387 break; 388 389 case SSCOP_RESYNC_confirm: 390 break; 391 392 case SSCOP_RETRIEVE_indication: 393 case SSCOP_RETRIEVE_COMPL_indication: 394 warnx("Ooops. A retrieve indication"); 395 abort(); 396 397 case SSCOP_ESTABLISH_request: 398 case SSCOP_RELEASE_request: 399 case SSCOP_ESTABLISH_response: 400 case SSCOP_DATA_request: 401 case SSCOP_UDATA_request: 402 case SSCOP_RECOVER_response: 403 case SSCOP_RESYNC_request: 404 case SSCOP_RESYNC_response: 405 case SSCOP_RETRIEVE_request: 406 warnx("bad signal for this direction"); 407 abort(); 408 } 409} 410 411/* 412 * This get's called for MAAL 413 */ 414static void 415sscop_send_manage(struct sscop *sscop __unused, void *arg __unused, 416 enum sscop_maasig sig, struct uni_msg *m, u_int error, u_int cnt) 417{ 418 VERBOSE(("--> got maa %d(%s)", sig, sscop_msigname(sig))); 419 420 switch (sig) { 421 422 case SSCOP_MDATA_indication: 423 VERBOSE(("MDATA.indication ignored")); 424 uni_msg_destroy(m); 425 break; 426 427 case SSCOP_MERROR_indication: 428 VERBOSE(("MAAL-ERROR.indication '%c' %u", error, cnt)); 429 break; 430 431 case SSCOP_MDATA_request: 432 warnx("bad signal for this direction"); 433 abort(); 434 } 435} 436