Virgin import of the NgATM SSCOP tool v0.9.

This commit is contained in:
Hartmut Brandt 2003-10-29 10:26:38 +00:00
parent e869973eec
commit f0be771edd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/ngatm/dist/; revision=121663
svn path=/vendor/ngatm/0.9/; revision=121665; tag=vendor/ngatm/0.9
4 changed files with 1107 additions and 0 deletions

View File

@ -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);
}

View File

@ -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_ */

169
contrib/ngatm/sscop/sscop.1 Normal file
View File

@ -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

View File

@ -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(&param, 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(&param, &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, &param, &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();
}
}