diff options
Diffstat (limited to 'contrib/ngatm/sscop')
-rw-r--r-- | contrib/ngatm/sscop/common.c | 431 | ||||
-rw-r--r-- | contrib/ngatm/sscop/common.h | 72 | ||||
-rw-r--r-- | contrib/ngatm/sscop/sscop.1 | 169 | ||||
-rw-r--r-- | contrib/ngatm/sscop/sscop_main.c | 435 |
4 files changed, 1107 insertions, 0 deletions
diff --git a/contrib/ngatm/sscop/common.c b/contrib/ngatm/sscop/common.c new file mode 100644 index 0000000..f1b9180 --- /dev/null +++ b/contrib/ngatm/sscop/common.c @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * 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 AUTHOR 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 AUTHOR 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. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/sscop/common.c,v 1.3 2003/09/19 13:10:35 hbb Exp $ + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <signal.h> +#include <assert.h> +#include <fcntl.h> +#include <err.h> +#include <isc/eventlib.h> + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscop.h> +#include "common.h" + +struct timer { + evTimerID id; + struct sscop *sscop; + void (*func)(void *); +}; + +int useframe; +int sscopframe; +u_int sscop_vflag; +int sscop_fd; +int user_fd; +int loose; +int user_out_fd; +u_int verbose; +evContext evctx; +evFileID sscop_h; +evFileID user_h; + +/* + * This function get's called from sscop to put out verbose messages + */ +void +sscop_verbose(struct sscop *sscop __unused, void *u __unused, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} +void +verb(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +/* + * Dump a buffer in hex to stderr. + */ +void +dump_buf(const char *w, const u_char *buf, size_t len) +{ + u_int i; + + fprintf(stderr, "%s %zu: ", w, len); + for(i = 0; i < len; i++) { + if (i % 4 == 0 && i != 0) + fprintf(stderr, " "); + fprintf(stderr, "%02x", *buf++); + } + fprintf(stderr, "\n"); +} + +/* + * SSCOP file descriptor is ready. Allocate and read one message + * and dispatch a signal. + */ +struct uni_msg * +proto_msgin(int fd __unused) +{ + struct uni_msg *m = NULL; + ssize_t size; + u_int32_t flen; + u_int got; + + if (sscopframe) { + if ((size = read(sscop_fd, &flen, 4)) == -1) + err(1, "error reading frame hdr"); + if (size == 0) { + got = 0; + goto eof; + } + if (size != 4) + errx(1, "short frame header: %zd", size); + if ((m = uni_msg_alloc(flen)) == NULL) + err(1, NULL); + for (got = 0; got < flen; got += (size_t)size) { + size = read(sscop_fd, m->b_rptr + got, flen - got); + if (size == -1) + err(1, "error reading frame"); + if (size == 0) { + got = 0; + break; + } + } + + } else { + if ((m = uni_msg_alloc(MAXMSG)) == NULL) + err(1, NULL); + if ((size = read(sscop_fd, m->b_rptr, MAXMSG)) == -1) + err(1, "error reading message"); + got = size; + } + + if (got == 0) { + eof: + evDeselectFD(evctx, sscop_h); + (void)close(sscop_fd); + sscop_fd = -1; + if (m != NULL) + uni_msg_destroy(m); + VERBOSE(("EOF on sscop file descriptor")); + return (NULL); + } + m->b_wptr = m->b_rptr + got; + + if(verbose & 0x0002) + dump_buf("SSCOP INPUT", m->b_rptr, got); + + return (m); +} + +/* + * User file descriptor ready - read a message + */ +struct uni_msg * +user_msgin(int fd __unused) +{ + struct uni_msg *m = NULL; + ssize_t size; + u_int32_t flen; + u_int got; + + if (useframe) { + if ((size = read(user_fd, &flen, 4)) == -1) + err(1, "error reading frame hdr"); + if (size == 0) { + got = 0; + goto eof; + } + if (size != 4) + errx(1, "short frame header: %zd", size); + if ((m = uni_msg_alloc(flen)) == NULL) + err(1, NULL); + for (got = 0; got < flen; got++) { + size = read(user_fd, m->b_rptr + got, flen - got); + if (size == -1) + err(1, "error reading frame"); + if (size == 0) { + got = 0; + break; + } + got += (size_t)size; + } + + } else { + if ((m = uni_msg_alloc(MAXMSG)) == NULL) + err(1, NULL); + if ((size = read(user_fd, m->b_rptr, MAXMSG)) == -1) + err(1, "error reading message"); + got = size; + } + + if (size == 0) { + eof: + evDeselectFD(evctx, user_h); + if (m != NULL) + uni_msg_destroy(m); + VERBOSE(("EOF on user connection")); + return (NULL); + } + m->b_wptr = m->b_rptr + size; + + return (m); +} + +/* + * Write message to the SSCOP file descriptor. + * Here we have a problem: we should have a means to check how much space + * we have. If the pipe is full, we could declare the lower layer busy and + * drop the message. However, how do we know, when a message will fit? + * Selecting for WRITE doesn't help, because it will return even if a single + * byte can be written. For this reason, we switch the file descriptor to + * blocking mode, and hope everything is fast enough to not timeout us. + * Alternatively we could just drop the message. Using kevent would help here. + */ +void +proto_msgout(struct uni_msg *m) +{ + struct iovec iov[2]; + u_int32_t flen; + ssize_t size; + static int sent; + int fl; + + if (verbose & 0x0002) + dump_buf("send", m->b_rptr, uni_msg_len(m)); + if (loose > 0 && (sent++ % loose) == loose - 1) { + VERBOSE(("loosing message")); + uni_msg_destroy(m); + return; + } + + flen = uni_msg_len(m); + + iov[0].iov_len = sscopframe ? 4 : 0; + iov[0].iov_base = (caddr_t)&flen; + iov[1].iov_len = uni_msg_len(m); + iov[1].iov_base = m->b_rptr; + + if ((fl = fcntl(sscop_fd, F_GETFL, 0)) == -1) + err(1, "cannot get flags for sscop fd"); + fl &= ~O_NONBLOCK; + if (fcntl(sscop_fd, F_SETFL, fl) == -1) + err(1, "cannot set flags for sscop fd"); + + if ((size = writev(sscop_fd, iov, 2)) == -1) + err(1, "write sscop"); + if ((size_t)size != iov[0].iov_len + iov[1].iov_len) + err(1, "short sscop write %zu %zu %zd", + iov[0].iov_len, iov[1].iov_len, size); + + fl |= O_NONBLOCK; + if (fcntl(sscop_fd, F_SETFL, fl) == -1) + err(1, "cannot restore flags for sscop fd"); + + uni_msg_destroy(m); +} + +/* + * output a message to the user + */ +void +user_msgout(struct uni_msg *m) +{ + struct iovec iov[2]; + u_int32_t flen; + ssize_t size; + + flen = uni_msg_len(m); + + iov[0].iov_len = useframe ? 4 : 0; + iov[0].iov_base = (caddr_t)&flen; + iov[1].iov_len = uni_msg_len(m); + iov[1].iov_base = m->b_rptr; + + if ((size = writev(user_out_fd, iov, 2)) == -1) + err(1, "write sscop"); + if ((size_t)size != iov[0].iov_len + iov[1].iov_len) + errx(1, "short sscop write"); + + uni_msg_destroy(m); +} + +void +parse_param(struct sscop_param *param, u_int *pmask, int opt, char *arg) +{ + u_int val; + char *end, *p; + + if(opt == 'b') { + param->flags |= SSCOP_ROBUST; + *pmask |= SSCOP_SET_ROBUST; + return; + } + if(opt == 'x') { + param->flags |= SSCOP_POLLREX; + *pmask |= SSCOP_SET_POLLREX; + return; + } + if(opt == 'W') { + val = (u_int)strtoul(optarg, &end, 0); + + if(*end != '\0') + errx(1, "bad number to -W '%s'", optarg); + if(val >= (1 << 24) - 1) + errx(1, "window too large: 0x%x", val); + param->mr = val; + *pmask |= SSCOP_SET_MR; + return; + } + + if((p = strchr(arg, '=')) == NULL) + errx(1, "need '=' in argument to -%c", opt); + *p++ = 0; + if(*p == 0) + errx(1, "argument to -%c %s empty", opt, arg); + val = strtoul(p, &end, 0); + if(*end != 0) + errx(1, "bad number in -%c %s=%s", opt, arg, p); + + if(opt == 't') { + if(strcmp(arg, "cc") == 0) { + param->timer_cc = val; + *pmask |= SSCOP_SET_TCC; + } else if(strcmp(arg, "poll") == 0) { + param->timer_poll = val; + *pmask |= SSCOP_SET_TPOLL; + } else if(strcmp(arg, "ka") == 0) { + param->timer_keep_alive = val; + *pmask |= SSCOP_SET_TKA; + } else if(strcmp(arg, "nr") == 0) { + param->timer_no_response = val; + *pmask |= SSCOP_SET_TNR; + } else if(strcmp(arg, "idle") == 0) { + param->timer_idle = val; + *pmask |= SSCOP_SET_TIDLE; + } else + errx(1, "bad timer name '%s'", arg); + return; + } + + if(opt == 'a') { + if(strcmp(arg, "j") == 0) { + param->maxj = val; + *pmask |= SSCOP_SET_MAXJ; + } else if(strcmp(arg, "k") == 0) { + param->maxk = val; + *pmask |= SSCOP_SET_MAXK; + } else if(strcmp(arg, "cc") == 0) { + param->maxcc = val; + *pmask |= SSCOP_SET_MAXCC; + } else if(strcmp(arg, "pd") == 0) { + param->maxpd = val; + *pmask |= SSCOP_SET_MAXPD; + } else if(strcmp(arg, "stat") == 0) { + param->maxstat = val; + *pmask |= SSCOP_SET_MAXSTAT; + } else + errx(1, "bad parameter '%s'", arg); + return; + } + + verb("bad flag"); + abort(); +} + +static void +tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, + struct timespec inter __unused) +{ + struct timer *t = uap; + + t->func(t->sscop); + free(t); +} + +/* + * Start a timer + */ +void * +sscop_start_timer(struct sscop *sscop, void *arg __unused, u_int msec, + void (*func)(void *)) +{ + struct timer *t; + struct timespec due; + + if ((t = malloc(sizeof(*t))) == NULL) + err(1, NULL); + t->sscop = sscop; + t->func = func; + + due = evAddTime(evNowTime(), + evConsTime((time_t)msec/1000, (long)(msec%1000)*1000)); + + if (evSetTimer(evctx, tfunc, t, due, evConsTime(0, 0), &t->id)) + err(1, "cannot start timer"); + + return (t); +} + +/* + * Stop a timer + */ +void +sscop_stop_timer(struct sscop *sscop __unused, void *arg __unused, void *tp) +{ + struct timer *t = tp; + + evClearTimer(evctx, t->id); + free(t); +} diff --git a/contrib/ngatm/sscop/common.h b/contrib/ngatm/sscop/common.h new file mode 100644 index 0000000..c4b02b8 --- /dev/null +++ b/contrib/ngatm/sscop/common.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * 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 AUTHOR 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 AUTHOR 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. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/sscop/common.h,v 1.3 2003/09/19 13:10:35 hbb Exp $ + * + * Common declaration for the SAAL programs. + */ +#ifndef _SAAL_COMMON_H_ +#define _SAAL_COMMON_H_ + +/* + * Writes to a pipe must be in messages (if we don't use framing). + * It is not clear, what is the maximum message size for this. It seems + * to be PIPE_BUF, but be conservative. + */ +#define MAXUSRMSG 4096 +#define MAXMSG (MAXUSRMSG+4) + +extern int useframe; /* use frame functions */ +extern int sscopframe; /* use sscop framing */ +extern u_int sscop_vflag; /* be talkative */ +extern int sscop_fd; /* file descriptor for SSCOP protocol */ +extern int user_fd; /* file descriptor for USER */ +extern int loose; /* loose messages */ +extern int user_out_fd; /* file descriptor for output to user */ +extern u_int verbose; /* talk to me */ +extern evContext evctx; +extern evFileID sscop_h; +extern evFileID user_h; + +void dump_buf(const char *, const u_char *, size_t); +struct uni_msg *proto_msgin(int); +struct uni_msg *user_msgin(int); +void proto_msgout(struct uni_msg *); +void user_msgout(struct uni_msg *); +void parse_param(struct sscop_param *, u_int *, int, char *); + +void verb(const char *, ...) __printflike(1, 2); + +void sscop_verbose(struct sscop *, void *, const char *, ...) + __printflike(3, 4); +void *sscop_start_timer(struct sscop *, void *, u_int, void (*)(void *)); +void sscop_stop_timer(struct sscop *, void *, void *); + +#define VERBOSE(P) do { if (verbose & 0x0001) verb P; } while(0) + +#endif /* _SAAL_COMMON_H_ */ diff --git a/contrib/ngatm/sscop/sscop.1 b/contrib/ngatm/sscop/sscop.1 new file mode 100644 index 0000000..db718b3 --- /dev/null +++ b/contrib/ngatm/sscop/sscop.1 @@ -0,0 +1,169 @@ +.\" +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" 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 AUTHOR 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 AUTHOR 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. +.\" +.\" Author: Harti Brandt <harti@freebsd.org> +.\" +.\" $Begemot: libunimsg/sscop/sscop.1,v 1.2 2003/08/21 16:01:08 hbb Exp $ +.\" +.Dd October 28, 2003 +.Dt SSCOP 1 +.Os +.Sh NAME +.Nm sscop +.Nd "SSCOP transport protocol" +.Sh SYNOPSIS +.Nm +.Op Fl Fbefhirwx3 +.Op Fl V Ar X +.Op Fl W Ar N +.Op Fl a Ar p Ns Li = Ns Ar v +.Op Fl l Ar N +.Op Fl t Ar t Ns Li = Ns Ar m +.Op Fl v Ar X +.Sh DESCRIPTION +The +.Nm +tool implements the Q.2110 transport protocol. +Normally the program reads from standard input and sends this input over +the SSCOP protocol on the standard output file descriptor. This means, that +the standard output file descriptor should be connected in read-write mode. +The program takes the +following arguments: +.Bl -tag -width ".It Fl a Ar p Ns Li = Ns Ar v" +.It Fl F +Use frameing on the SSCOP connection (see the +.Fl f +option). +.It Fl V Ar X +Set the verbose flag to the hex value +.Ar X . +.It Fl W Ar N +Set the initial SSCOP window to +.Ar N . +.It Fl a Ar p Ns Li = Ns Ar v +Set SSCOP parameter +.Ar p +to the value +.Ar v . +The following parameters may be set: +.Bl -tag -width ".It Li stat Ns = Ns Ar N" +.It Li j Ns = Ns Ar N +Set the maximum SSCOP-UU data size to +.Ar N +octets. +.It Li k Ns = Ns Ar N +Set the maximum SSCOP SDU data size to +.Ar N +octets. +.It Li cc Ns = Ns Ar N +Set the parameter +.Li MaxCC +(maximum number of connection control message re-transmissions) to +the value +.Ar N . +.It Li pd Ns = Ns Ar N +Set the parameter +.Li MaxPD +(maximum acceptable number of outstanding unacknowledged SD PDUs before +sending a POLL) to the value +.Ar N . +.It Li stat Ns = Ns Ar N +Set the parameter +.Li MaxSTAT +(maximum number of elements placed in a STAT PDU) to the value +.Ar N . +.El +.It Fl b +Enable the ATM-Forum SSCOP robustness enhancement. +.It Fl e +Exit when there is an end of file condition on the input file or the +SSCOP indicates a release confirmation. +.It Fl f +Use the framing protocol for communication over the SSCOP link. See +.Xr frame l +(libbegemot) for framing. +.It Fl h +Print a short help information and exit. +.It Fl i +Try not to read from the user input file descriptor. Assume that we a receiving +only. +.It Fl l Ar N +Loose every Nth message. This is used for testing. +.It Fl r +Revert user and SSCOP file descriptors. That means, that user input and output +is done on standard output and SSCOP input and output on standard input. +.It Fl t Ar t Ns Li = Ns Ar m +Set SSCOP timer +.Ar t +to +.Ar m +milliseconds. The following timers may be set: +.Bl -tag -width ".It Li stat Ns = Ns Ar N" +.It Li cc Ns = Ns Ar m +Set the connection control timer to +.Ar m . +This timer controls the retransmission of connection control messages. +.It Li poll Ns = Ns Ar m +Set the poll timer to +.Ar m . +This timer controls the transmission of POLL messages. +.It Li ka Ns = Ns Ar m +Set the keep-alive timer to +.Ar m . +This timer controls the maximum length of the transient phase. +.It Li nr Ns = Ns Ar m +Set the no-response timer to +.Ar m . +This timer controls the maximum time between two received STAT PDUs before +the connection is aborted. +.It Li idle Ns = Ns Ar m +Set the idle timer to +.Ar m . +This timer controls the length of the idle phase. +.El +.It Fl v Ar X +Set the SSCOP library verbose flag to the hex value. +.It Fl w +Don't start the SSCOP protocol. Wait for a establish indication from the remote +side. +.It Fl x +Enable to POLL after retransmission flag. +.It Fl 3 +Send user output to file descriptor 3. +.El +.Sh EXAMPLES +The following command line sends the file +.Pa Makefile +over a pipe (this depends on the feature that pipes are bi-directional): +.Bd -literal +cat Makefile | sscop -reF | sscop -weF +.Ed +.Sh SEE ALSO +.Xr libunimsg 3 +.Sh STANDARDS +The implemented protocol conforms to ITU-T recommendation Q.2110. +.Sh AUTHORS +.An Hartmut Brandt Aq harti@freebsd.org diff --git a/contrib/ngatm/sscop/sscop_main.c b/contrib/ngatm/sscop/sscop_main.c new file mode 100644 index 0000000..c426535 --- /dev/null +++ b/contrib/ngatm/sscop/sscop_main.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * 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 AUTHOR 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 AUTHOR 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. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/sscop/sscop_main.c,v 1.3 2003/09/19 13:10:35 hbb Exp $ + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <signal.h> +#include <assert.h> +#include <err.h> +#include <isc/eventlib.h> + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscop.h> +#include "common.h" + +static int sigusr1; /* got SIGUSR1 */ +static int unidir; /* write only user */ +static int end_at_eof = 1; /* send RELEASE_request at user EOF */ + +static volatile int ready; /* flag if connection is established */ +static volatile int finished; /* got release confirm or indication */ + +static const char usgtxt[] = "\ +SSCOP transport protocol\n\ +Usage: sscop [-h] [-Fbefirwx3] [-ap=v] [-lN] [-tt=m] [-v X] [-V X] [-W N]\n\ +Options:\n\ + -F use framing for sscop also\n\ + -V X set verbose flags to hex X\n\ + -W N set initial window to N\n\ + -a p=v set parameter 'p' to 'v'\n\ + -b enable robustness enhancement\n\ + -e don't RELEASE_request on user EOF\n\ + -f use begemot frame functions for user fd\n\ + -h print this info\n\ + -i use user fd only for output\n\ + -lN loose every nth message\n\ + -r reverse user and sscop file descriptors\n\ + -t t=m set timer 't' to 'm' milliseconds\n\ + -v X set sscop verbose flags to hex X\n\ + -w don't start conversation\n\ + -x enable POLL after retransmission\n\ + -3 redirect output to fd 3\n\ +Timers are cc, poll, ka, nr or idle; parameters are j, k, cc, pd or stat.\n"; + +static void sscop_send_manage(struct sscop *, void *, + enum sscop_maasig, struct uni_msg *, u_int, u_int); +static void sscop_send_upper(struct sscop *, void *, enum sscop_aasig, + struct SSCOP_MBUF_T *, u_int); +static void sscop_send_lower(struct sscop *, void *, struct SSCOP_MBUF_T *); + +static const struct sscop_funcs sscop_funcs = { + sscop_send_manage, + sscop_send_upper, + sscop_send_lower, + sscop_verbose, + sscop_start_timer, + sscop_stop_timer +}; + +/* + * SSCOP file descriptor is ready. Allocate and read one message + * and dispatch a signal. + */ +static void +proto_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused) +{ + struct uni_msg *m; + + if ((m = proto_msgin(fd)) != NULL) + sscop_input((struct sscop *)uap, m); +} + +/* + * User input. Allocate and read message and dispatch signal. + */ +static void +user_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused) +{ + struct uni_msg *m; + + if ((m = user_msgin(fd)) != NULL) + sscop_aasig((struct sscop *)uap, SSCOP_DATA_request, m, 0); + + else if (end_at_eof) + sscop_aasig((struct sscop *)uap, SSCOP_RELEASE_request, 0, 0); +} + +static void +onusr1(int s __unused) +{ + sigusr1++; +} + +int +main(int argc, char *argv[]) +{ + int opt; + struct sscop *sscop; + struct sscop_param param; + struct sigaction sa; + int wait = 0; + u_int mask; + evEvent ev; + + /* + * Default is to have the USER on stdin and SSCOP on stdout + */ + sscop_fd = 0; + user_fd = 1; + user_out_fd = -1; + + memset(¶m, 0, sizeof(param)); + param.maxk = MAXUSRMSG; + param.maxj = 0; + param.maxcc = 4; + mask = SSCOP_SET_MAXK | SSCOP_SET_MAXJ | SSCOP_SET_MAXCC; + + while((opt = getopt(argc, argv, "3a:befFhil:rt:v:V:wW:x")) != -1) + switch(opt) { + + case '3': + user_out_fd = 3; + break; + + case 'e': + end_at_eof = 0; + break; + + case 'f': + useframe = 1; + break; + + case 'F': + sscopframe = 1; + break; + + case 'h': + fprintf(stderr, usgtxt); + exit(0); + + case 'i': + unidir++; + break; + + case 'l': + loose = strtoul(optarg, NULL, 0); + break; + + case 'r': + sscop_fd = 1; + user_fd = 0; + break; + + case 'v': + sscop_vflag = strtoul(optarg, NULL, 16); + break; + + case 'V': + verbose = strtoul(optarg, NULL, 16); + break; + + case 'w': + wait = 1; + break; + + case 'a': + case 't': + case 'b': + case 'x': + case 'W': + parse_param(¶m, &mask, opt, optarg); + break; + } + + if(user_out_fd < 0) + user_out_fd = user_fd; + + if (evCreate(&evctx)) + err(1, "evCreate"); + + /* + * Catch USR1 + */ + sa.sa_handler = onusr1; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if(sigaction(SIGUSR1, &sa, NULL)) + err(1, "sigaction(SIGUSR1)"); + + /* + * Allocate and initialize SSCOP + */ + if ((sscop = sscop_create(NULL, &sscop_funcs)) == NULL) + err(1, NULL); + sscop_setdebug(sscop, sscop_vflag); + if ((errno = sscop_setparam(sscop, ¶m, &mask)) != 0) + err(1, "can't set sscop parameters %#x", mask); + + /* + * Register sscop fd + */ + if (evSelectFD(evctx, sscop_fd, EV_READ, proto_infunc, sscop, &sscop_h)) + err(1, "can't select on sscop fd"); + + /* + * if we are active - send establish request + */ + if(!wait) + sscop_aasig(sscop, SSCOP_ESTABLISH_request, NULL, 1); + + /* + * Run protocol until it get's ready + */ + while (sscop_fd >= 0 && !ready) { + if (evGetNext(evctx, &ev, EV_WAIT) == 0) { + if (evDispatch(evctx, ev)) + err(1, "dispatch event"); + } else if (errno != EINTR) + err(1, "get event"); + } + + /* + * If this led to a closed file - exit. + */ + if (sscop_fd < 0) { + VERBOSE(("SSCOP file descriptor closed - exiting")); + sscop_destroy(sscop); + return 0; + } + + VERBOSE(("READY - starting data transfer")); + + if (!unidir && + evSelectFD(evctx, user_fd, EV_READ, user_infunc, sscop, &user_h)) + err(1, "can't select on sscop fd"); + + while (!sigusr1 && sscop_fd >= 0) { + if (evGetNext(evctx, &ev, EV_WAIT) == 0) { + if (evDispatch(evctx, ev)) + err(1, "dispatch event"); + } else if (errno != EINTR) + err(1, "get event"); + } + + if (sigusr1 && sscop_fd >= 0) { + /* + * Release if we still have the connection + */ + sscop_aasig(sscop, SSCOP_RELEASE_request, NULL, 0); + while (!finished && sscop_fd >= 0) { + if (evGetNext(evctx, &ev, EV_WAIT) == 0) { + if (evDispatch(evctx, ev)) + err(1, "dispatch event"); + } else if (errno != EINTR) + err(1, "get event"); + } + } + + VERBOSE(("SSCOP file descriptor closed - exiting")); + sscop_destroy(sscop); + + return (0); +} + + + +/* + * AAL OUTPUT + */ +static void +sscop_send_lower(struct sscop *sscop __unused, void *arg __unused, + struct SSCOP_MBUF_T *m) +{ + proto_msgout(m); +} + + +/* + * Write the message to the user and move the window + */ +static void +uoutput(struct sscop *sscop, struct uni_msg *m) +{ + user_msgout(m); + sscop_window(sscop, +1); +} + +/* + * SSCOP AA-SIGNALS + */ +static void +sscop_send_upper(struct sscop *sscop, void *arg __unused, enum sscop_aasig sig, + struct SSCOP_MBUF_T *m, u_int p __unused) +{ + VERBOSE(("--> got aa %d(%s)", sig, sscop_signame(sig))); + + switch (sig) { + + case SSCOP_RELEASE_indication: + if (end_at_eof) { + VERBOSE((" ... exiting")); + evDeselectFD(evctx, sscop_h); + (void)close(sscop_fd); + sscop_fd = -1; + } + finished++; + if (m) + uni_msg_destroy(m); + break; + + case SSCOP_RELEASE_confirm: + if (end_at_eof) { + VERBOSE((" ... exiting")); + evDeselectFD(evctx, sscop_h); + (void)close(sscop_fd); + sscop_fd = -1; + } + finished++; + break; + + case SSCOP_ESTABLISH_indication: + sscop_aasig(sscop, SSCOP_ESTABLISH_response, NULL, 1); + ready++; + if (m) + uni_msg_destroy(m); + break; + + case SSCOP_ESTABLISH_confirm: + ready++; + if (m) + uni_msg_destroy(m); + break; + + case SSCOP_DATA_indication: + assert(m != NULL); + uoutput(sscop, m); + break; + + case SSCOP_UDATA_indication: + assert(m != NULL); + VERBOSE(("UDATA.indication ignored")); + uni_msg_destroy(m); + break; + + case SSCOP_RECOVER_indication: + sscop_aasig(sscop, SSCOP_RECOVER_response, NULL, 0); + break; + + case SSCOP_RESYNC_indication: + sscop_aasig(sscop, SSCOP_RESYNC_response, NULL, 0); + if (m) + uni_msg_destroy(m); + break; + + case SSCOP_RESYNC_confirm: + break; + + case SSCOP_RETRIEVE_indication: + case SSCOP_RETRIEVE_COMPL_indication: + warnx("Ooops. A retrieve indication"); + abort(); + + case SSCOP_ESTABLISH_request: + case SSCOP_RELEASE_request: + case SSCOP_ESTABLISH_response: + case SSCOP_DATA_request: + case SSCOP_UDATA_request: + case SSCOP_RECOVER_response: + case SSCOP_RESYNC_request: + case SSCOP_RESYNC_response: + case SSCOP_RETRIEVE_request: + warnx("bad signal for this direction"); + abort(); + } +} + +/* + * This get's called for MAAL + */ +static void +sscop_send_manage(struct sscop *sscop __unused, void *arg __unused, + enum sscop_maasig sig, struct uni_msg *m, u_int error, u_int cnt) +{ + VERBOSE(("--> got maa %d(%s)", sig, sscop_msigname(sig))); + + switch (sig) { + + case SSCOP_MDATA_indication: + VERBOSE(("MDATA.indication ignored")); + uni_msg_destroy(m); + break; + + case SSCOP_MERROR_indication: + VERBOSE(("MAAL-ERROR.indication '%c' %u", error, cnt)); + break; + + case SSCOP_MDATA_request: + warnx("bad signal for this direction"); + abort(); + } +} |