| OpenSS7 SS7 for the Common Man | © Copyright 1997-2007 OpenSS7 Corporation All Rights Reserved. Last modified: Sun, 03 Aug 2008 22:23:24 GMT | ||||||||||||||||
| |||||||||||||||||
| Description: CodeFile /code/strxnet/src/lib/xnet.c
#ident "@(#) xnet.c,v openss7-0_9_2_F(0.9.2.28) 2007/05/22 02:10:38"
static char const ident[] =
"xnet.c,v openss7-0_9_2_F(0.9.2.28) 2007/05/22 02:10:38";
#define _XOPEN_SOURCE 600
#define _REENTRANT
#define _THREAD_SAFE
#if 0
#define __USE_UNIX98
#define __USE_XOPEN2K
#define __USE_GNU
#endif
#define _SC_T_DEFAULT_ADDRLEN 2
#define _SC_T_DEFAULT_CONNLEN 3
#define _SC_T_DEFAULT_DISCLEN 4
#define _SC_T_DEFAULT_OPTLEN 5
#define _SC_T_DEFAULT_DATALEN 6
#define _T_DEFAULT_ADDRLEN 128
#define _T_DEFAULT_CONNLEN 256
#define _T_DEFAULT_DISCLEN 256
#define _T_DEFAULT_OPTLEN 256
#define _T_DEFAULT_DATALEN 16384
#define _T_TIMEOUT -1
#define _T_IOV_MAX 16
#define NEED_T_USCALAR_T 1
#include <stdlib.h>
#include "gettext.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#include <sys/stropts.h>
#include <sys/poll.h>
#include <fcntl.h>
#if 0
#pragma weak getpmsg
#pragma weak putpmsg
#pragma weak getmsg
#pragma weak putmsg
#pragma weak isastream
#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#else
# ifdef HAVE_STDINT_H
# include <stdint.h>
# endif
#endif
#ifndef __EXCEPTIONS
#define __EXCEPTIONS 1
#endif
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stropts.h>
#include <pthread.h>
#include <linux/limits.h>
#include <values.h>
#ifndef __P
#define __P(__prototype) __prototype
#endif
#include <xti.h>
#include <tihdr.h>
#include <timod.h>
#if defined __i386__ || defined __x86_64__ || defined __k8__
#define fastcall __attribute__((__regparm__(3)))
#else
#define fastcall
#endif
#define __hot __attribute__((section(".text.hot")))
#define __unlikely __attribute__((section(".text.unlikely")))
#if __GNUC__ < 3
#define inline inline fastcall __hot
#define noinline extern fastcall __unlikely
#else
#define inline inline __attribute__((always_inline)) fastcall __hot
#define noinline static __attribute__((noinline)) fastcall __unlikely
#endif
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#undef min
#define min(a, b) (a < b ? a : b)
struct __xnet_tsd {
int terrno;
};
static pthread_once_t __xnet_tsd_once = PTHREAD_ONCE_INIT;
static pthread_key_t __xnet_tsd_key = 0;
static void
__xnet_tsd_free(void *buf)
{
pthread_setspecific(__xnet_tsd_key, NULL);
free(buf);
}
static void
__xnet_tsd_alloc(void)
{
int ret;
void *buf;
ret = pthread_key_create(&__xnet_tsd_key, __xnet_tsd_free);
buf = malloc(sizeof(struct __xnet_tsd));
bzero(buf, sizeof(*buf));
ret = pthread_setspecific(__xnet_tsd_key, buf);
return;
}
static struct __xnet_tsd *
__xnet_get_tsd(void)
{
pthread_once(&__xnet_tsd_once, __xnet_tsd_alloc);
return (struct __xnet_tsd *) pthread_getspecific(__xnet_tsd_key);
};
int *
__xnet__t_errno(void)
{
return &(__xnet_get_tsd()->terrno);
}
__asm__(".symver __xnet__t_errno,_t_errno@@XNET_1.0");
struct _t_user {
pthread_rwlock_t lock;
int refs;
int event;
int flags;
int fflags;
int gflags;
int state;
int statef;
int prim;
int qlen;
int ocnt;
u_int8_t moredat;
u_int8_t moresdu;
u_int8_t moreexp;
u_int8_t moreedu;
u_int8_t moremsg;
int ctlmax;
char *ctlbuf;
int datmax;
char *datbuf;
uint token;
struct strbuf ctrl;
struct strbuf data;
struct t_info info;
};
#define TUF_FLOW_NORM 01
#define TUF_FLOW_EXP 02
#define TUF_SYNC_REQUIRED 04
#define TUF_WACK_INFO 010
#define TUF_WACK_OPTMGMT 020
#define TUF_WACK_ADDR 040
#define TUF_WACK_CAPABILITY 0100
#define TUF_WACK_GETADDR 0200
#define TUF_WACK_OK 0400
#define TUF_WACK_BIND 01000
#define TUF_MORE_DATA 02000
#ifndef T_ACK
#define T_ACK (-2)
#endif
static struct _t_user *_t_fds[OPEN_MAX] = { NULL, };
#define TSF_UNBND (1 << TS_UNBND )
#define TSF_WACK_BREQ (1 << TS_WACK_BREQ )
#define TSF_WACK_UREQ (1 << TS_WACK_UREQ )
#define TSF_IDLE (1 << TS_IDLE )
#define TSF_WACK_OPTREQ (1 << TS_WACK_OPTREQ )
#define TSF_WACK_CREQ (1 << TS_WACK_CREQ )
#define TSF_WCON_CREQ (1 << TS_WCON_CREQ )
#define TSF_WRES_CIND (1 << TS_WRES_CIND )
#define TSF_WACK_CRES (1 << TS_WACK_CRES )
#define TSF_DATA_XFER (1 << TS_DATA_XFER )
#define TSF_WIND_ORDREL (1 << TS_WIND_ORDREL )
#define TSF_WREQ_ORDREL (1 << TS_WREQ_ORDREL )
#define TSF_WACK_DREQ6 (1 << TS_WACK_DREQ6 )
#define TSF_WACK_DREQ7 (1 << TS_WACK_DREQ7 )
#define TSF_WACK_DREQ9 (1 << TS_WACK_DREQ9 )
#define TSF_WACK_DREQ10 (1 << TS_WACK_DREQ10 )
#define TSF_WACK_DREQ11 (1 << TS_WACK_DREQ11 )
static inline void
__xnet_u_setstate_const(struct _t_user *user, const int state)
{
user->statef = (1 << state);
switch (state) {
case TS_UNBND:
case TS_WACK_BREQ:
user->state = T_UNBND;
break;
case TS_WACK_UREQ:
case TS_IDLE:
case TS_WACK_CREQ:
user->state = T_IDLE;
break;
case TS_WCON_CREQ:
case TS_WACK_DREQ6:
user->state = T_OUTCON;
break;
case TS_WRES_CIND:
case TS_WACK_CRES:
case TS_WACK_DREQ7:
user->state = T_INCON;
break;
case TS_DATA_XFER:
case TS_WACK_DREQ9:
user->state = T_DATAXFER;
break;
case TS_WIND_ORDREL:
case TS_WACK_DREQ10:
user->state = T_OUTREL;
break;
case TS_WREQ_ORDREL:
case TS_WACK_DREQ11:
user->state = T_INREL;
break;
default:
user->state = T_UNINIT;
}
}
static void
__xnet_u_setstate(struct _t_user *user, int state)
{
user->statef = (1 << state);
switch (state) {
case TS_UNBND:
case TS_WACK_BREQ:
user->state = T_UNBND;
break;
case TS_WACK_UREQ:
case TS_IDLE:
case TS_WACK_CREQ:
user->state = T_IDLE;
break;
case TS_WCON_CREQ:
case TS_WACK_DREQ6:
user->state = T_OUTCON;
break;
case TS_WRES_CIND:
case TS_WACK_CRES:
case TS_WACK_DREQ7:
user->state = T_INCON;
break;
case TS_DATA_XFER:
case TS_WACK_DREQ9:
user->state = T_DATAXFER;
break;
case TS_WIND_ORDREL:
case TS_WACK_DREQ10:
user->state = T_OUTREL;
break;
case TS_WREQ_ORDREL:
case TS_WACK_DREQ11:
user->state = T_INREL;
break;
default:
user->state = T_UNINIT;
}
}
static inline int
__xnet_u_setevent(struct _t_user *user, int prim, int flags)
{
switch ((user->prim = prim)) {
case -1:
return (user->event = T_DATA);
case T_CONN_IND:
return (user->event = T_LISTEN);
case T_CONN_CON:
return (user->event = T_CONNECT);
case T_DISCON_IND:
return (user->event = T_DISCONNECT);
case T_DATA_IND:
return (user->event = T_DATA);
case T_EXDATA_IND:
return (user->event = T_EXDATA);
case T_UNITDATA_IND:
return (user->event = T_DATA);
case T_UDERROR_IND:
return (user->event = T_UDERR);
case T_ORDREL_IND:
return (user->event = T_ORDREL);
case T_OPTDATA_IND:
return (user->event = (flags & T_ODF_EX) ? T_EXDATA : T_DATA);
default:
return (user->event = 0);
}
}
static void
__xnet_u_reset_event(struct _t_user *user)
{
if (user->event != T_EXDATA || (!user->moresdu && !user->moredat)) {
user->prim = 0;
user->event = 0;
user->ctrl.maxlen = user->ctlmax;
user->ctrl.len = 0;
user->ctrl.buf = user->ctlbuf;
user->data.maxlen = user->datmax;
user->data.len = 0;
user->data.buf = user->datbuf;
user->moredat = 0;
user->moresdu = 0;
user->moreexp = 0;
user->moreedu = 0;
user->moremsg = 0;
} else {
user->prim = 0;
user->event = T_DATA;
user->ctrl.maxlen = user->ctlmax;
user->ctrl.len = 0;
user->ctrl.buf = user->ctlbuf;
user->data.maxlen = user->datmax;
user->data.len = 0;
user->data.buf = user->datbuf;
user->moreexp = 0;
user->moreedu = 0;
user->moremsg = 0;
}
}
static inline int
__xnet_u_max_addr(struct _t_user *user)
{
return (user->info.addr == T_INFINITE
? MAXINT : (user->info.addr >= 0 ? user->info.addr : 0));
}
static inline int
__xnet_u_max_options(struct _t_user *user)
{
return (user->info.options == T_INFINITE
? MAXINT : (user->info.options >= 0 ? user->info.options : 0));
}
static inline int
__xnet_u_max_tsdu(struct _t_user *user)
{
return ((user->info.tsdu == T_INFINITE || user->info.tsdu == 0)
? MAXINT : (user->info.tsdu >= 0 ? user->info.tsdu : 0));
}
static inline int
__xnet_u_max_etsdu(struct _t_user *user)
{
return ((user->info.etsdu == T_INFINITE || user->info.etsdu == 0)
? MAXINT : (user->info.etsdu >= 0 ? user->info.etsdu : 0));
}
static inline int
__xnet_u_max_connect(struct _t_user *user)
{
return (user->info.connect == T_INFINITE
? MAXINT : (user->info.connect >= 0 ? user->info.connect : 0));
}
static inline int
__xnet_u_max_discon(struct _t_user *user)
{
return (user->info.discon == T_INFINITE
? MAXINT : (user->info.discon >= 0 ? user->info.discon : 0));
}
static inline int
__xnet_u_max_tidu(struct _t_user *user)
{
return (user->info.tidu == T_INFINITE
? MAXINT : (user->info.tidu >= 0 ? user->info.tidu : 0));
}
static int __xnet_t_getmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int *flagsp);
static int __xnet_t_putmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int flags);
static int __xnet_t_putpmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int band, int flags);
static int __xnet_t_ioctl(int fd, int cmd, void *arg);
static int __xnet_t_strioctl(int fd, int cmd, void *arg, size_t arglen);
#if 0
int __xnet_t_accept(int fd, int resfd, const struct t_call *call);
int __xnet_t_addleaf(int fd, int leafid, struct netbuf *addr);
char *__xnet_t_alloc(int fd, int type, int fields);
int __xnet_t_bind(int fd, const struct t_bind *req, struct t_bind *ret);
int __xnet_t_close(int fd);
int __xnet_t_connect(int fd, const struct t_call *sndcall, struct t_call *rcvcall);
int __xnet_t_free(void *ptr, int type);
int __xnet_t_getinfo(int fd, struct t_info *info);
int __xnet_t_getstate(int fd);
int __xnet_t_listen(int fd, struct t_call *call);
int __xnet_t_look(int fd);
int __xnet_t_open(const char *path, int oflag, struct t_info *info);
int __xnet_t_optmgmt(int fd, const struct t_optmgmt *req, struct t_optmgmt *ret);
int __xnet_t_rcv(int fd, char *buf, unsigned int nbytes, int *flags);
int __xnet_t_rcvconnect(int fd, struct t_call *call);
int __xnet_t_rcvdis(int fd, struct t_discon *discon);
int __xnet_t_rcvleafchange(int fd, struct t_leaf_status *change);
int __xnet_t_rcvrel(int fd);
int __xnet_t_rcvreldata(int fd, struct t_discon *discon);
int __xnet_t_rcvopt(int fd, struct t_unitdata *optdata, int *flags);
int __xnet_t_rcvudata(int fd, struct t_unitdata *unitdata, int *flags);
int __xnet_t_rcvv(int fd, struct t_iovec *iov, unsigned int iovcount, int *flags);
int __xnet_t_rcvvudata(int fd, struct t_unitdata *unitdata, struct t_iovec *iov,
unsigned int iovcount, int *flags);
int __xnet_t_removeleaf(int fd, int leafid, int reason);
int __xnet_t_snd(int fd, char *buf, unsigned int nbytes, int flags);
int __xnet_t_snddis(int fd, const struct t_call *call);
int __xnet_t_sndrel(int fd);
int __xnet_t_sndreldata(int fd, struct t_discon *discon);
int __xnet_t_sndopt(int fd, const struct t_unitdata *optdata, int flags);
int __xnet_t_sndvopt(int fd, const struct t_unitdata *optdata, const struct t_iovec *iov,
unsigned int iovcount, int flags);
int __xnet_t_sndudata(int fd, const struct t_unitdata *unitdata);
int __xnet_t_sndv(int fd, const struct t_iovec *iov, unsigned int iovcount, int flags);
int __xnet_t_sndvudata(int fd, struct t_unitdata *unitdata, struct t_iovec *iov,
unsigned int iovcount);
int __xnet_t_sysconf(int name);
int __xnet_t_unbind(int fd);
const char *__xnet_t_strerror(int errnum);
#endif
#if 0
int __xnet_t_accept_r(int fd, int resfd, const struct t_call *call);
int __xnet_t_addleaf_r(int fd, int leafid, struct netbuf *addr);
char *__xnet_t_alloc_r(int fd, int type, int fields);
int __xnet_t_bind_r(int fd, const struct t_bind *req, struct t_bind *ret);
int __xnet_t_close_r(int fd);
int __xnet_t_connect_r(int fd, const struct t_call *sndcall, struct t_call *rcvcall);
int __xnet_t_getinfo_r(int fd, struct t_info *info);
int __xnet_t_getstate_r(int fd);
int __xnet_t_listen_r(int fd, struct t_call *call);
int __xnet_t_look_r(int fd);
int __xnet_t_open_r(const char *path, int oflag, struct t_info *info);
int __xnet_t_optmgmt_r(int fd, const struct t_optmgmt *req, struct t_optmgmt *ret);
int __xnet_t_rcv_r(int fd, char *buf, unsigned int nbytes, int *flags);
int __xnet_t_rcvconnect_r(int fd, struct t_call *call);
int __xnet_t_rcvdis_r(int fd, struct t_discon *discon);
int __xnet_t_rcvleafchange_r(int fd, struct t_leaf_status *change);
int __xnet_t_rcvrel_r(int fd);
int __xnet_t_rcvreldata_r(int fd, struct t_discon *discon);
int __xnet_t_rcvopt_r(int fd, struct t_unitdata *optdata, int *flags);
int __xnet_t_rcvudata_r(int fd, struct t_unitdata *unitdata, int *flags);
int __xnet_t_rcvv_r(int fd, struct t_iovec *iov, unsigned int iovcount, int *flags);
int __xnet_t_rcvvudata_r(int fd, struct t_unitdata *unitdata, struct t_iovec *iov,
unsigned int iovcount, int *flags);
int __xnet_t_removeleaf_r(int fd, int leafid, int reason);
int __xnet_t_snd_r(int fd, char *buf, unsigned int nbytes, int flags);
int __xnet_t_snddis_r(int fd, const struct t_call *call);
int __xnet_t_sndrel_r(int fd);
int __xnet_t_sndreldata_r(int fd, struct t_discon *discon);
int __xnet_t_sndopt_r(int fd, const struct t_unitdata *optdata, int flags);
int __xnet_t_sndvopt_r(int fd, const struct t_unitdata *optdata, const struct t_iovec *iov,
unsigned int iovcount, int flags);
int __xnet_t_sndudata_r(int fd, const struct t_unitdata *unitdata);
int __xnet_t_sndv_r(int fd, const struct t_iovec *iov, unsigned int iovcount, int flags);
int __xnet_t_sndvudata_r(int fd, struct t_unitdata *unitdata, struct t_iovec *iov,
unsigned int iovcount);
int __xnet_t_unbind_r(int fd);
#endif
static int
__xnet_t_getmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int *flagsp)
{
int ret;
if ((ret = getmsg(fd, ctrl, data, flagsp)) >= 0)
return (ret);
t_errno = TSYSERR;
switch (errno) {
case EISDIR:
case EBADF:
t_errno = TBADF;
break;
case EFAULT:
case ENODEV:
case ENOSTR:
case EIO:
case EINVAL:
break;
case EAGAIN:
t_errno = TNODATA;
return (0);
case EINTR:
case ENOSR:
case EBADMSG:
break;
}
return (-1);
}
static __hot int
__xnet_t_putmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int flags)
{
int ret;
if ((ret = putmsg(fd, ctrl, data, flags)) >= 0)
return (ret);
t_errno = TSYSERR;
switch (errno) {
case EAGAIN:
t_errno = TFLOW;
break;
case EISDIR:
case EBADF:
t_errno = TBADF;
break;
case EFAULT:
case EINTR:
case EINVAL:
case EIO:
case ENODEV:
case ENOSR:
case ENOSTR:
case ENXIO:
case ERANGE:
break;
}
return (-1);
}
static int
__xnet_t_putpmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int band, int flags)
{
int ret;
if ((ret = putpmsg(fd, ctrl, data, band, flags)) != -1)
return (ret);
t_errno = TSYSERR;
switch (errno) {
case EAGAIN:
t_errno = TFLOW;
break;
case EISDIR:
case EBADF:
t_errno = TBADF;
break;
case EFAULT:
case EINTR:
case EINVAL:
case EIO:
case ENODEV:
case ENOSR:
case ENOSTR:
case ENXIO:
case ERANGE:
break;
}
return (-1);
}
static __hot int
__xnet_t_getdata(int fd, struct strbuf *udata, int expect)
{
struct _t_user *user = _t_fds[fd];
int ret, flag = 0;
union T_primitives *p = (typeof(p)) user->ctlbuf;
if (likely(user->event == T_DATA) || likely(user->event == T_EXDATA)) {
if (unlikely(!(user->event & expect)))
goto done;
if (unlikely(user->data.len < 1))
goto getmoredata;
udata->len = min(udata->maxlen, user->data.len);
memcpy(udata->buf, user->data.buf, udata->len);
user->data.buf += udata->len;
user->data.len -= udata->len;
} else if (user->event == 0) {
__xnet_u_reset_event(user);
getmoredata:
user->data.maxlen = min(udata->maxlen, user->datmax);
user->data.len = 0;
user->data.buf = udata->buf;
if ((ret = __xnet_t_getmsg(fd, &user->ctrl, &user->data, &flag)) < 0)
goto error;
if (user->ctrl.len < 0)
user->ctrl.len = 0;
if (user->data.len < 0)
user->data.len = 0;
udata->len = user->data.len;
if (ret & MORECTL)
goto cleanup;
if (flag != 0 || flag == RS_HIPRI)
goto tsync;
if (user->ctrl.len || user->data.len) {
if (user->event == 0 || user->ctrl.len > 0)
__xnet_u_setevent(user, user->ctrl.len ? p->type : -1, 0);
switch (user->prim) {
case -1:
user->moredat = ((ret & MOREDATA) != 0);
break;
case T_DATA_IND:
user->moresdu = (p->data_ind.MORE_flag != 0);
user->moredat = ((ret & MOREDATA) != 0);
break;
case T_EXDATA_IND:
user->moreedu = (p->exdata_ind.MORE_flag != 0);
user->moreexp = ((ret & MOREDATA) != 0);
break;
case T_OPTDATA_IND:
if (p->optdata_ind.DATA_flag & T_ODF_EX) {
user->moreedu =
((p->optdata_ind.DATA_flag & T_ODF_MORE) != 0);
user->moreexp = ((ret & MOREDATA) != 0);
} else {
user->moresdu =
((p->optdata_ind.DATA_flag & T_ODF_MORE) != 0);
user->moredat = ((ret & MOREDATA) != 0);
}
break;
case T_UNITDATA_IND:
user->moresdu = 0;
user->moredat = ((ret & MOREDATA) != 0);
user->moreedu = 0;
user->moreexp = 0;
break;
case T_CONN_IND:
case T_CONN_CON:
case T_DISCON_IND:
case T_ORDREL_IND:
case T_UDERROR_IND:
user->moremsg = ((ret & MOREDATA) != 0);
break;
}
if ((user->event & expect))
user->data.len = 0;
else {
if (user->data.len > 0)
memcpy(user->datbuf, user->data.buf, user->data.len);
user->data.buf = user->datbuf;
udata->len = 0;
}
}
} else
goto tlook;
done:
return (user->event);
cleanup:
while (ret != -1 && (ret & (MORECTL | MOREDATA)))
ret = __xnet_t_getmsg(fd, &user->ctrl, &user->data, &flag);
goto tsync;
tlook:
t_errno = TLOOK;
goto error;
tsync:
__xnet_u_reset_event(user);
user->flags |= TUF_SYNC_REQUIRED;
goto tproto;
tproto:
t_errno = TPROTO;
goto error;
error:
return (-1);
}
static int
__xnet_t_getevent(int fd)
{
struct _t_user *user = _t_fds[fd];
int ret, flag = 0;
union T_primitives *p = (typeof(p)) user->ctlbuf;
switch (user->event) {
case 0:
__xnet_u_reset_event(user);
if ((ret = __xnet_t_getmsg(fd, &user->ctrl, &user->data, &flag)) < 0)
goto error;
if (ret & MORECTL)
goto cleanup;
if (flag != 0 || flag == RS_HIPRI)
goto tsync;
if (user->ctrl.len || user->data.len) {
__xnet_u_setevent(user, user->ctrl.len ? p->type : -1, 0);
switch (user->prim) {
case -1:
user->moredat = ((ret & MOREDATA) != 0);
break;
case T_DATA_IND:
user->moresdu = (p->data_ind.MORE_flag != 0);
user->moredat = ((ret & MOREDATA) != 0);
break;
case T_EXDATA_IND:
user->moreedu = (p->exdata_ind.MORE_flag != 0);
user->moreexp = ((ret & MOREDATA) != 0);
break;
case T_OPTDATA_IND:
if (p->optdata_ind.DATA_flag & T_ODF_EX) {
user->moreedu =
((p->optdata_ind.DATA_flag & T_ODF_MORE) != 0);
user->moreexp = ((ret & MOREDATA) != 0);
} else {
user->moresdu =
((p->optdata_ind.DATA_flag & T_ODF_MORE) != 0);
user->moredat = ((ret & MOREDATA) != 0);
}
break;
case T_UNITDATA_IND:
user->moresdu = 0;
user->moredat = ((ret & MOREDATA) != 0);
user->moreedu = 0;
user->moreexp = 0;
break;
case T_CONN_IND:
case T_CONN_CON:
case T_DISCON_IND:
case T_ORDREL_IND:
case T_UDERROR_IND:
user->moremsg = ((ret & MOREDATA) != 0);
break;
}
}
}
return (user->event);
cleanup:
while (ret != -1 && (ret & (MORECTL | MOREDATA)))
ret = __xnet_t_getmsg(fd, &user->ctrl, &user->data, &flag);
goto tsync;
tsync:
__xnet_u_reset_event(user);
user->flags |= TUF_SYNC_REQUIRED;
goto tproto;
tproto:
t_errno = TPROTO;
goto error;
error:
return (-1);
}
static pthread_rwlock_t __xnet_fd_lock = PTHREAD_RWLOCK_INITIALIZER;
static inline int
__xnet_lock_rdlock(pthread_rwlock_t * rwlock)
{
return pthread_rwlock_rdlock(rwlock);
}
static inline int
__xnet_lock_wrlock(pthread_rwlock_t * rwlock)
{
return pthread_rwlock_wrlock(rwlock);
}
static inline void
__xnet_lock_unlock(void *rwlock)
{
pthread_rwlock_unlock(rwlock);
}
static inline int
__xnet_list_rdlock(void)
{
return __xnet_lock_rdlock(&__xnet_fd_lock);
}
static int
__xnet_list_wrlock(void)
{
return __xnet_lock_wrlock(&__xnet_fd_lock);
}
static void
__xnet_list_unlock(void *ignore)
{
return __xnet_lock_unlock(&__xnet_fd_lock);
}
#if 0
static int
__xnet_user_rdlock(struct _t_user *user)
{
return __xnet_lock_rdlock(&user->lock);
}
#endif
static inline int
__xnet_user_wrlock(struct _t_user *user)
{
return __xnet_lock_wrlock(&user->lock);
}
static inline void
__xnet_user_unlock(struct _t_user *user)
{
return __xnet_lock_unlock(&user->lock);
}
static void
__xnet_t_putuser(void *arg)
{
int fd = *(int *) arg;
struct _t_user *user = _t_fds[fd];
__xnet_user_unlock(user);
__xnet_list_unlock(NULL);
return;
}
static __hot struct _t_user *
__xnet_t_getuser(int fd)
{
struct _t_user *user;
int err;
if (unlikely((err = __xnet_list_rdlock())))
goto list_lock_error;
if (unlikely(0 > fd) || unlikely(fd >= OPEN_MAX))
goto tbadf;
if (unlikely(!(user = _t_fds[fd])))
goto tbadf;
if (unlikely((err = __xnet_user_wrlock(user))))
goto user_lock_error;
return (user);
user_lock_error:
t_errno = TSYSERR;
errno = err;
__xnet_list_unlock(NULL);
goto error;
tbadf:
t_errno = TBADF;
goto error;
list_lock_error:
t_errno = TSYSERR;
errno = err;
goto error;
error:
return (NULL);
}
static __hot struct _t_user *
__xnet_t_tstuser(int fd, const int expect, const int servtype, const int states)
{
struct _t_user *user;
if (unlikely(0 > fd) || unlikely(fd >= OPEN_MAX))
goto tbadf;
if (unlikely(!(user = _t_fds[fd])))
goto tbadf;
if (unlikely(user->flags & TUF_SYNC_REQUIRED))
goto tproto;
if (unlikely(user->event && user->event != expect && expect != -1))
goto tlook;
#ifndef CONFIG_XTI_IS_TYPELESS
if (unlikely(!((1 << user->info.servtype) & servtype)))
goto tnotsupport;
#endif
#ifndef CONFIG_XTI_IS_STATELESS
if (unlikely(!(user->statef & states)))
goto toutstate;
#endif
return (user);
#ifndef CONFIG_XTI_IS_STATELESS
toutstate:
t_errno = TOUTSTATE;
goto error;
#endif
#ifndef CONFIG_XTI_IS_TYPELESS
tnotsupport:
t_errno = TNOTSUPPORT;
goto error;
#endif
tlook:
t_errno = TLOOK;
goto error;
tproto:
t_errno = TPROTO;
goto error;
tbadf:
t_errno = TBADF;
goto error;
error:
return (NULL);
}
static int
__xnet_t_ioctl(int fd, int cmd, void *arg)
{
int ret;
switch ((ret = ioctl(fd, cmd, arg))) {
case 0:
return (0);
case -1:
switch (errno) {
case EBADF:
case ENOTTY:
case EINVAL:
case EPERM:
t_errno = TBADF;
break;
default:
t_errno = TSYSERR;
break;
}
return (-1);
default:
if ((t_errno = ret & 0x00ff) == TSYSERR)
if (!(errno = (ret >> 8) & 0x00ff))
errno = EINVAL;
return (-1);
}
}
static int
__xnet_t_strioctl(int fd, int cmd, void *arg, size_t arglen)
{
struct strioctl ioc;
ioc.ic_cmd = cmd;
ioc.ic_timout = _T_TIMEOUT;
ioc.ic_len = arglen;
ioc.ic_dp = arg;
return __xnet_t_ioctl(fd, I_STR, &ioc);
}
int
__xnet_t_accept(int fd, int resfd, const struct t_call *call)
{
struct _t_user *user, *resuser;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD), TSF_WRES_CIND)))
goto error;
if (fd == resfd) {
resuser = user;
if (user->ocnt > 1)
goto tindout;
if (user->ocnt < 1)
goto tproto;
} else
if (!(resuser = __xnet_t_tstuser(resfd, 0, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_UNBND | TSF_IDLE)))
goto error;
if (__xnet_t_look(fd) > 0)
goto tlook;
if (__xnet_t_look(resfd) > 0)
goto tlook;
#ifdef DEBUG
if (!call)
goto einval;
if (call->addr.len < 0 || (call->addr.len > 0 && !call->addr.buf))
goto einval;
if (call->opt.len < 0 || (call->opt.len > 0 && !call->opt.buf))
goto einval;
if (call->udata.len < 0 || (call->udata.len > 0 && !call->udata.buf))
goto einval;
#endif
if (call && call->addr.len > __xnet_u_max_addr(user))
goto tbadaddr;
if (call && call->opt.len > __xnet_u_max_options(user))
goto tbadopt;
if (call && call->udata.len > __xnet_u_max_connect(user))
goto tbaddata;
if (resuser->statef & TSF_UNBND) {
size_t add_len = (call && call->addr.len > 0) ? call->addr.len : 0;
struct {
struct T_bind_req prim;
unsigned char addr[add_len];
} req;
req.prim.PRIM_type = T_BIND_REQ;
req.prim.ADDR_length = add_len;
req.prim.ADDR_offset = add_len ? sizeof(req.prim) : 0;
req.prim.CONIND_number = 0;
if (add_len)
memcpy(req.addr, call->addr.buf, add_len);
if (__xnet_t_strioctl(resfd, TI_BIND, &req, sizeof(req)) != 0)
goto error;
__xnet_u_setstate_const(resuser, TS_IDLE);
}
{
size_t opt_len = (call && call->opt.len > 0) ? call->opt.len : 0;
size_t dat_len = (call && call->udata.len > 0) ? call->udata.len : 0;
struct {
struct T_conn_res prim;
unsigned char opt[opt_len];
unsigned char udata[dat_len];
} req;
req.prim.PRIM_type = T_CONN_RES;
req.prim.ACCEPTOR_id = resuser->token;
req.prim.OPT_length = opt_len;
req.prim.OPT_offset = opt_len ? sizeof(req.prim) : 0;
req.prim.SEQ_number = call ? call->sequence : 0;
if (opt_len)
memcpy(req.opt, call->opt.buf, opt_len);
if (dat_len > 0)
memcpy(req.opt + opt_len, call->udata.buf, dat_len);
if (__xnet_t_strioctl(fd, TI_SETMYNAME, &req, sizeof(req)) != 0)
goto error;
__xnet_u_setstate_const(resuser, TS_DATA_XFER);
if (user->ocnt && !--user->ocnt)
if (user != resuser)
__xnet_u_setstate_const(user, TS_IDLE);
}
return (0);
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbadaddr:
t_errno = TBADADDR;
goto error;
tbadopt:
t_errno = TBADOPT;
goto error;
tbaddata:
t_errno = TBADDATA;
goto error;
tproto:
t_errno = TPROTO;
goto error;
tlook:
t_errno = TLOOK;
goto error;
tindout:
t_errno = TINDOUT;
goto error;
error:
if (t_errno != TLOOK && (__xnet_t_look(fd) > 0 || __xnet_t_look(resfd) > 0))
goto tlook;
return (-1);
}
int
__xnet_t_accept_r(int fd, int resfd, const struct t_call *call)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_accept(fd, resfd, call);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_accept_r,t_accept@@XNET_1.0");
int
__xnet_t_addleaf(int fd, int leafid, struct netbuf *addr)
{
#if defined HAVE_XTI_ATM_H
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD), TSF_DATA_XFER)))
goto error;
#ifdef DEBUG
if (!addr)
goto einval;
if (addr->len < 0 || (addr->len > 0 && !addr->buf))
goto einval;
#endif
if (!addr || addr->len < sizeof(struct t_atm_addr))
goto tbadaddr;
{
struct {
struct t_opthdr hdr;
struct t_atm_add_leaf leaf;
} opts;
struct t_optmgmt req, ret;
req.opt.maxlen = 0;
req.opt.len = sizeof(opts);
req.opt.buf = (char *) &opts;
req.flags = T_CURRENT;
ret.opt.maxlen = sizeof(opts);
ret.opt.len = 0;
ret.opt.buf = (char *) &opts;
ret.flags = 0;
opts.hdr.len = sizeof(opts);
opts.hdr.level = T_ATM_SIGNALLING;
opts.hdr.name = T_ATM_ADD_LEAF;
opts.hdr.status = 0;
opts.leaf.leaf_ID = leafid;
memcpy(&opt.leaf.leaf_address, addr->buf, addr->len);
if (__xnet_t_optmgmt(fd, &req, &ret) == -1)
goto error;
if (ret.opt.flags == T_FAILURE)
goto tproto;
if (ret.opt.len < sizeof(opts) || opts.hdr.len < sizeof(opts))
goto tproto;
if (opts.hdr.status != T_SUCCESS)
goto tproto;
if (opts.hdr.level != T_ATM_SIGNALLING || opts.hdr.name != T_ATM_ADD_LEAF)
goto tproto;
goto tnodata;
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tnodata:
t_errno = TNODATA;
goto error;
tbadaddr:
t_errno = TBADADDR;
goto error;
error:
return (-1);
#else
t_errno = TNOTSUPPORT;
return (-1);
#endif
}
#pragma weak __xnet_t_addleaf_r
int
__xnet_t_addleaf_r(int fd, int leafid, struct netbuf *addr)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_addleaf(fd, leafid, addr);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_addleaf_r,t_addleaf@@XNET_1.0");
char *
__xnet_t_alloc(int fd, int type, int fields)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, -1, -1)))
goto error;
switch (type) {
case T_BIND:
{
struct t_bind *bind;
if (!(bind = (struct t_bind *) malloc(sizeof(*bind))))
goto badalloc;
memset(bind, 0, sizeof(*bind));
if (fields & T_ADDR) {
int len;
switch ((len = user->info.addr)) {
case T_INFINITE:
len = _T_DEFAULT_ADDRLEN;
default:
if (!(bind->addr.buf = (char *) malloc(len))) {
free(bind);
goto badalloc;
}
bind->addr.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
free(bind);
goto einval;
}
break;
}
}
return ((char *) bind);
}
case T_OPTMGMT:
{
struct t_optmgmt *opts;
if (!(opts = (struct t_optmgmt *) malloc(sizeof(*opts))))
goto badalloc;
memset(opts, 0, sizeof(*opts));
if (fields & T_OPT) {
int len;
switch ((len = user->info.options)) {
case T_INFINITE:
len = _T_DEFAULT_OPTLEN;
default:
if (!(opts->opt.buf = (char *) malloc(len))) {
free(opts);
goto badalloc;
}
opts->opt.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
free(opts);
goto einval;
}
break;
}
}
return ((char *) opts);
}
case T_CALL:
{
struct t_call *call;
#ifndef CONFIG_XTI_IS_TYPELESS
if (user->info.servtype == T_CLTS)
goto tnostructype;
#endif
if (!(call = (struct t_call *) malloc(sizeof(*call))))
goto badalloc;
memset(call, 0, sizeof(*call));
if (fields & T_ADDR) {
int len;
switch ((len = user->info.addr)) {
case T_INFINITE:
len = _T_DEFAULT_ADDRLEN;
default:
if (!(call->addr.buf = (char *) malloc(len))) {
free(call);
goto badalloc;
}
call->addr.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
free(call);
goto einval;
}
break;
}
}
if (fields & T_OPT) {
int len;
switch ((len = user->info.options)) {
case T_INFINITE:
len = _T_DEFAULT_OPTLEN;
default:
if (!(call->opt.buf = (char *) malloc(len))) {
if (call->addr.buf)
free(call->addr.buf);
free(call);
goto badalloc;
}
call->opt.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
if (call->addr.buf)
free(call->addr.buf);
free(call);
goto einval;
}
break;
}
}
if (fields & T_UDATA) {
int len;
switch ((len = user->info.connect)) {
case T_INFINITE:
len = _T_DEFAULT_CONNLEN;
default:
if (!(call->udata.buf = (char *) malloc(len))) {
if (call->addr.buf)
free(call->addr.buf);
if (call->opt.buf)
free(call->opt.buf);
free(call);
goto badalloc;
}
call->udata.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
if (call->addr.buf)
free(call->addr.buf);
if (call->opt.buf)
free(call->opt.buf);
free(call);
goto einval;
}
break;
}
}
return ((char *) call);
}
case T_DIS:
{
struct t_discon *discon;
#ifndef CONFIG_XTI_IS_TYPELESS
if (user->info.servtype == T_CLTS)
goto tnostructype;
#endif
if (!(discon = (struct t_discon *) malloc(sizeof(*discon))))
goto badalloc;
memset(discon, 0, sizeof(*discon));
if (fields & T_UDATA) {
int len;
switch ((len = user->info.discon)) {
case T_INFINITE:
len = _T_DEFAULT_DISCLEN;;
default:
if (!(discon->udata.buf = (char *) malloc(len))) {
free(discon);
goto badalloc;
}
discon->udata.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
free(discon);
goto einval;
}
break;
}
}
return ((char *) discon);
}
case T_UNITDATA:
{
struct t_unitdata *udata;
#ifndef CONFIG_XTI_IS_TYPELESS
if (user->info.servtype != T_CLTS)
goto tnostructype;
#endif
if (!(udata = (struct t_unitdata *) malloc(sizeof(*udata))))
goto badalloc;
memset(udata, 0, sizeof(*udata));
if (fields & T_ADDR) {
int len;
switch ((len = user->info.addr)) {
case T_INFINITE:
len = _T_DEFAULT_ADDRLEN;
default:
if (!(udata->addr.buf = (char *) malloc(len))) {
free(udata);
goto badalloc;
}
udata->addr.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
free(udata);
goto einval;
}
break;
}
}
if (fields & T_OPT) {
int len;
switch ((len = user->info.options)) {
case T_INFINITE:
len = _T_DEFAULT_OPTLEN;
default:
if (!(udata->opt.buf = (char *) malloc(len))) {
if (udata->addr.buf)
free(udata->addr.buf);
free(udata);
goto badalloc;
}
udata->opt.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
if (udata->addr.buf)
free(udata->addr.buf);
free(udata);
goto einval;
}
break;
}
}
if (fields & T_UDATA) {
int len;
switch ((len = user->info.tsdu)) {
case T_INFINITE:
case 0:
len = _T_DEFAULT_DATALEN;
default:
if (!(udata->udata.buf = (char *) malloc(len))) {
if (udata->addr.buf)
free(udata->addr.buf);
if (udata->opt.buf)
free(udata->opt.buf);
free(udata);
goto badalloc;
}
udata->udata.maxlen = len;
break;
case T_INVALID:
if (fields != T_ALL) {
if (udata->addr.buf)
free(udata->addr.buf);
if (udata->opt.buf)
free(udata->opt.buf);
free(udata);
goto einval;
}
break;
}
}
return ((char *) udata);
}
case T_UDERROR:
{
struct t_uderr *uderr;
#ifndef CONFIG_XTI_IS_TYPELESS
if (user->info.servtype != T_CLTS)
goto tnostructype;
#endif
if (!(uderr = (struct t_uderr *) malloc(sizeof(*uderr))))
goto badalloc;
memset(uderr, 0, sizeof(*uderr));
if (fields & T_ADDR) {
int len;
switch ((len = user->info.addr)) {
case T_INFINITE:
len = _T_DEFAULT_ADDRLEN;
default:
if (!(uderr->addr.buf = (char *) malloc(len))) {
free(uderr);
goto badalloc;
}
uderr->addr.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
free(uderr);
goto einval;
}
break;
}
}
if (fields & T_OPT) {
int len;
switch ((len = user->info.options)) {
case T_INFINITE:
len = _T_DEFAULT_OPTLEN;
default:
if (!(uderr->opt.buf = (char *) malloc(len))) {
if (uderr->addr.buf)
free(uderr->addr.buf);
free(uderr);
goto badalloc;
}
uderr->opt.maxlen = len;
case 0:
break;
case T_INVALID:
if (fields != T_ALL) {
if (uderr->addr.buf)
free(uderr->addr.buf);
free(uderr);
goto einval;
}
break;
}
}
return ((char *) uderr);
}
case T_INFO:
{
struct t_info *inf;
if (!(inf = (struct t_info *) malloc(sizeof(*inf))))
goto badalloc;
memset(inf, 0, sizeof(*inf));
return ((char *) inf);
}
default:
goto tnostructype;
}
tnostructype:
t_errno = TNOSTRUCTYPE;
goto error;
einval:
t_errno = TSYSERR;
errno = EINVAL;
goto error;
badalloc:
t_errno = TSYSERR;
goto error;
error:
return ((char *) NULL);
}
char *
__xnet_t_alloc_r(int fd, int type, int fields)
{
char *ret = NULL;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_alloc(fd, type, fields);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_alloc_r,t_alloc@@XNET_1.0");
int
__xnet_t_bind(int fd, const struct t_bind *req, struct t_bind *ret)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, -1, TSF_UNBND)))
goto error;
#ifdef DEBUG
if (req && (req->addr.len < 0 || (req->addr.len > 0 && !req->addr.buf)))
goto einval;
if (ret && (req->addr.maxlen < 0 || (ret->addr.maxlen > 0 && !ret->addr.buf)))
goto einval;
#endif
if (req && req->addr.len > __xnet_u_max_addr(user))
goto tbadaddr;
{
size_t add_len = (req && req->addr.len > 0) ? req->addr.len : 0;
size_t add_max = min(__xnet_u_max_addr(user), _T_DEFAULT_ADDRLEN);
size_t qlen = (req && req->qlen > 0) ? req->qlen : 0;
union {
struct {
struct T_bind_req prim;
unsigned char addr[add_len];
} req;
struct {
struct T_bind_ack prim;
unsigned char addr[add_max];
} ack;
} buf;
buf.req.prim.PRIM_type = T_BIND_REQ;
buf.req.prim.ADDR_length = add_len;
buf.req.prim.ADDR_offset = add_len ? sizeof(buf.req.prim) : 0;
buf.req.prim.CONIND_number = qlen;
if (add_len)
memcpy(buf.req.addr, req->addr.buf, add_len);
if (__xnet_t_strioctl(fd, TI_BIND, &buf, sizeof(buf)) != 0)
goto error;
__xnet_u_setstate_const(user, TS_IDLE);
user->qlen = buf.ack.prim.CONIND_number;
if (ret) {
if (ret->addr.maxlen > 0) {
if (ret->addr.maxlen < buf.ack.prim.ADDR_length)
goto tbufovflw;
if ((ret->addr.len = buf.ack.prim.ADDR_length))
memcpy(ret->addr.buf,
((char *) &buf) + buf.ack.prim.ADDR_offset,
ret->addr.len);
}
ret->qlen = buf.ack.prim.CONIND_number;
}
return (0);
}
tbufovflw:
t_errno = TBUFOVFLW;
goto error;
tbadaddr:
t_errno = TBADADDR;
goto error;
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto tsyserr;
#endif
error:
return (-1);
}
int
__xnet_t_bind_r(int fd, const struct t_bind *req, struct t_bind *ret)
{
int rtv = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
rtv = __xnet_t_bind(fd, req, ret);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (rtv);
}
__asm__(".symver __xnet_t_bind_r,t_bind@@XNET_1.0");
int
__xnet_t_close(int fd)
{
struct _t_user *user;
int ret;
if (!(user = __xnet_t_tstuser(fd, -1, -1, -1)))
goto error;
if ((ret = close(fd)) == 0 || errno != EINTR) {
if (--user->refs == 0) {
_t_fds[fd] = NULL;
pthread_rwlock_destroy(&user->lock);
if (user->ctlbuf)
free(user->ctlbuf);
if (user->datbuf)
free(user->datbuf);
free(user);
}
}
if (ret == 0)
return (0);
if (errno == EINTR)
t_errno = TSYSERR;
error:
return (-1);
}
int
__xnet_t_close_r(int fd)
{
int err, ret = -1;
pthread_cleanup_push_defer_np(__xnet_list_unlock, NULL);
if ((err = __xnet_list_wrlock()) == 0) {
ret = __xnet_t_close(fd);
__xnet_list_unlock(NULL);
} else {
t_errno = TSYSERR;
errno = err;
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_close_r,t_close@@XNET_1.0");
int
__xnet_t_connect(int fd, const struct t_call *sndcall, struct t_call *rcvcall)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD), TSF_IDLE)))
goto error;
if (__xnet_t_look(fd) > 0)
goto tlook;
#ifdef DEBUG
if (!sndcall)
goto einval;
if (sndcall->addr.len < 0 || (sndcall->addr.len > 0 && !sndcall->addr.buf))
goto einval;
if (sndcall->opt.len < 0 || (sndcall->opt.len > 0 && !sndcall->opt.buf))
goto einval;
if (sndcall->udata.len < 0 || (sndcall->udata.len > 0 && !sndcall->udata.buf))
goto einval;
if (rcvcall
&& (rcvcall->addr.maxlen < 0 || (rcvcall->addr.maxlen > 0 && !rcvcall->addr.buf)))
goto einval;
if (rcvcall && (rcvcall->opt.maxlen < 0 || (rcvcall->opt.maxlen > 0 && !rcvcall->opt.buf)))
goto einval;
if (rcvcall
&& (rcvcall->udata.maxlen < 0 || (rcvcall->udata.maxlen > 0 && !rcvcall->udata.buf)))
goto einval;
#endif
if (sndcall && sndcall->addr.len > __xnet_u_max_addr(user))
goto tbadaddr;
if (sndcall && sndcall->opt.len > __xnet_u_max_options(user))
goto tbadopt;
if (sndcall && sndcall->udata.len > __xnet_u_max_connect(user))
goto tbaddata;
{
size_t add_len = (sndcall && sndcall->addr.len > 0) ? sndcall->addr.len : 0;
size_t opt_len = (sndcall && sndcall->opt.len > 0) ? sndcall->opt.len : 0;
size_t dat_len = (sndcall && sndcall->udata.len > 0) ? sndcall->udata.len : 0;
struct {
struct T_conn_req prim;
unsigned char addr[add_len];
unsigned char opt[opt_len];
unsigned char udata[dat_len];
} req;
req.prim.PRIM_type = T_CONN_REQ;
req.prim.DEST_length = add_len;
req.prim.DEST_offset = add_len ? sizeof(req.prim) : 0;
req.prim.OPT_length = opt_len;
req.prim.OPT_offset = opt_len ? sizeof(req.prim) + add_len : 0;
if (add_len)
memcpy(req.addr, sndcall->addr.buf, add_len);
if (opt_len)
memcpy(req.addr + add_len, sndcall->opt.buf, opt_len);
if (dat_len)
memcpy(req.addr + add_len + opt_len, sndcall->udata.buf, dat_len);
if (__xnet_t_strioctl(fd, TI_SETPEERNAME, &req, sizeof(req)))
goto error;
__xnet_u_setstate_const(user, TS_WCON_CREQ);
}
return __xnet_t_rcvconnect(fd, rcvcall);
tlook:
t_errno = TLOOK;
goto error;
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbadaddr:
t_errno = TBADADDR;
goto error;
tbadopt:
t_errno = TBADOPT;
goto error;
tbaddata:
t_errno = TBADDATA;
goto error;
error:
if (t_errno != TLOOK && __xnet_t_look(fd) > 0)
goto tlook;
return (-1);
}
int
__xnet_t_connect_r(int fd, const struct t_call *sndcall, struct t_call *rcvcall)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_connect(fd, sndcall, rcvcall)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_connect_r,t_connect@@XNET_1.0");
int
__xnet_t_error(const char *errmsg)
{
fprintf(stderr, "%s: %s\n", errmsg, __xnet_t_strerror(t_errno));
return (0);
}
int
__xnet_t_error_r(const char *errmsg)
{
int oldtype, ret;
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
ret = __xnet_t_error(errmsg);
pthread_setcanceltype(oldtype, NULL);
return (ret);
}
__asm__(".symver __xnet_t_error_r,t_error@@XNET_1.0");
int
__xnet_t_free(void *ptr, int type)
{
if (!ptr)
goto einval;
switch (type) {
case T_BIND:
{
struct t_bind *bind = (struct t_bind *) ptr;
if (bind->addr.buf)
free(bind->addr.buf);
free(bind);
return (0);
}
case T_OPTMGMT:
{
struct t_optmgmt *opts = (struct t_optmgmt *) ptr;
if (opts->opt.buf)
free(opts->opt.buf);
free(opts);
return (0);
}
case T_CALL:
{
struct t_call *call = (struct t_call *) ptr;
if (call->addr.buf)
free(call->addr.buf);
if (call->opt.buf)
free(call->opt.buf);
if (call->udata.buf)
free(call->udata.buf);
free(call);
return (0);
}
case T_DIS:
{
struct t_discon *discon = (struct t_discon *) ptr;
if (discon->udata.buf)
free(discon->udata.buf);
free(discon);
return (0);
}
case T_UNITDATA:
{
struct t_unitdata *unitdata = (struct t_unitdata *) ptr;
if (unitdata->addr.buf)
free(unitdata->addr.buf);
if (unitdata->opt.buf)
free(unitdata->opt.buf);
if (unitdata->udata.buf)
free(unitdata->udata.buf);
return (0);
}
case T_UDERROR:
{
struct t_uderr *uderr = (struct t_uderr *) ptr;
if (uderr->addr.buf)
free(uderr->addr.buf);
if (uderr->opt.buf)
free(uderr->opt.buf);
free(uderr);
return (0);
}
case T_INFO:
{
struct t_info *info = (struct t_info *) ptr;
free(info);
return (0);
}
default:
goto tnostructype;
}
tnostructype:
t_errno = TNOSTRUCTYPE;
goto error;
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
error:
return (-1);
}
__asm__(".symver __xnet_t_free,t_free@@XNET_1.0");
int
__xnet_t_getinfo(int fd, struct t_info *info)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, -1, -1)))
goto error;
#ifdef DEBUG
if (!info)
goto einval;
#endif
{
union {
struct T_info_req req;
struct T_info_ack ack;
} buf;
buf.req.PRIM_type = T_INFO_REQ;
if (__xnet_t_strioctl(fd, TI_GETINFO, &buf, sizeof(buf)) != 0)
goto error;
user->info.addr = buf.ack.ADDR_size;
user->info.options = buf.ack.OPT_size;
user->info.tsdu = buf.ack.TSDU_size;
user->info.etsdu = buf.ack.ETSDU_size;
user->info.connect = buf.ack.CDATA_size;
user->info.discon = buf.ack.DDATA_size;
user->info.servtype = buf.ack.SERV_type;
user->info.flags = buf.ack.PROVIDER_flag;
user->info.tidu = buf.ack.TIDU_size;
if (info)
*info = user->info;
return (0);
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
error:
return (-1);
}
int
__xnet_t_getinfo_r(int fd, struct t_info *info)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_getinfo(fd, info);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_getinfo_r,t_getinfo@@XNET_1.0");
int
__xnet_t_getprotaddr(int fd, struct t_bind *loc, struct t_bind *rem)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, -1, -1)))
goto error;
{
size_t add_max = min(__xnet_u_max_addr(user), _T_DEFAULT_ADDRLEN);
union {
struct {
struct T_addr_req prim;
} req;
struct {
struct T_addr_ack prim;
unsigned char loc[add_max];
unsigned char rem[add_max];
} ack;
} buf;
buf.req.prim.PRIM_type = T_ADDR_REQ;
if (__xnet_t_strioctl(fd, TI_GETADDRS, &buf, sizeof(buf)) != 0)
goto error;
if (loc && loc->addr.maxlen < buf.ack.prim.LOCADDR_length)
goto tbufovflw;
if (rem && rem->addr.maxlen < buf.ack.prim.REMADDR_length)
goto tbufovflw;
if (loc && (loc->addr.len = buf.ack.prim.LOCADDR_length))
memcpy(loc->addr.buf, (char *) &buf + buf.ack.prim.LOCADDR_offset,
loc->addr.len);
if (rem && (rem->addr.len = buf.ack.prim.REMADDR_length))
memcpy(rem->addr.buf, (char *) &buf + buf.ack.prim.REMADDR_offset,
rem->addr.len);
return (0);
}
tbufovflw:
t_errno = TBUFOVFLW;
goto error;
error:
return (-1);
}
int
__xnet_t_getprotaddr_r(int fd, struct t_bind *loc, struct t_bind *rem)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_getprotaddr(fd, loc, rem);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_getprotaddr_r,t_getprotaddr@@XNET_1.0");
int
__xnet_t_getstate(int fd)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, -1, -1, -1)))
goto error;
if (user->statef & (TSF_UNBND | TSF_IDLE | TSF_WCON_CREQ | TSF_WRES_CIND | TSF_DATA_XFER |
TSF_WREQ_ORDREL | TSF_WIND_ORDREL)) {
return (user->state);
}
if (user->statef & (TSF_WACK_DREQ6 | TSF_WACK_DREQ7 | TSF_WACK_DREQ9 | TSF_WACK_DREQ10 |
TSF_WACK_DREQ11 | TSF_WACK_BREQ | TSF_WACK_UREQ | TSF_WACK_CREQ |
TSF_WACK_CRES))
goto tstatechng;
goto tproto;
tstatechng:
t_errno = TSTATECHNG;
goto error;
tproto:
user->flags |= TUF_SYNC_REQUIRED;
t_errno = TPROTO;
goto error;
error:
return (-1);
}
int
__xnet_t_getstate_r(int fd)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_getstate(fd);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_getstate_r,t_getstate@@XNET_1.0");
int
__xnet_t_listen(int fd, struct t_call *call)
{
struct _t_user *user;
if (!
(user =
__xnet_t_tstuser(fd, T_LISTEN, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_WRES_CIND | TSF_IDLE)))
goto error;
if ((user->statef & TSF_IDLE) && user->qlen <= 0)
goto tbadqlen;
if (user->ocnt >= user->qlen)
goto tqfull;
switch (__xnet_t_getevent(fd)) {
case T_LISTEN:
{
union T_primitives *p = (typeof(p)) user->ctrl.buf;
__xnet_u_setstate_const(user, TS_WRES_CIND);
user->ocnt++;
if (call) {
call->sequence = p->conn_ind.SEQ_number;
if (call->addr.maxlen && call->addr.maxlen < p->conn_ind.SRC_length)
goto tbufovflw;
if (call->opt.maxlen && call->opt.maxlen < p->conn_ind.OPT_length)
goto tbufovflw;
if (call->udata.maxlen && call->udata.maxlen < user->data.len)
goto tbufovflw;
if (call->addr.maxlen && (call->addr.len = p->conn_ind.SRC_length))
memcpy(call->addr.buf, (char *) p + p->conn_ind.SRC_offset,
call->addr.len);
if (call->opt.maxlen && (call->opt.len = p->conn_ind.OPT_length))
memcpy(call->opt.buf, (char *) p + p->conn_ind.OPT_offset,
call->opt.len);
if (call->udata.maxlen && (call->udata.len = user->data.len))
memcpy(call->udata.buf, user->data.buf, call->udata.len);
}
__xnet_u_reset_event(user);
return (0);
}
case 0:
goto tnodata;
case -1:
goto error;
default:
goto tlook;
}
tlook:
t_errno = TLOOK;
goto error;
tnodata:
t_errno = TNODATA;
goto error;
tbufovflw:
__xnet_u_reset_event(user);
t_errno = TBUFOVFLW;
goto error;
tqfull:
t_errno = TQFULL;
goto error;
tbadqlen:
t_errno = TBADQLEN;
goto error;
error:
if (t_errno != TLOOK && __xnet_t_look(fd) > 0)
goto tlook;
return (-1);
}
int
__xnet_t_listen_r(int fd, struct t_call *call)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_listen(fd, call)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_listen_r,t_listen@@XNET_1.0");
int
__xnet_t_look(int fd)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, -1, -1, -1)))
goto error;
if (user->event == 0) {
struct pollfd pfd;
pfd.fd = fd;
pfd.events =
(POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND | POLLMSG | POLLERR | POLLHUP);
pfd.revents = 0;
switch (poll(&pfd, 1, 0)) {
case 1:
if (pfd.revents & (POLLMSG | POLLERR | POLLHUP))
break;
if (pfd.revents & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND))
break;
case 0:
return (0);
case -1:
goto tsyserr;
default:
goto tproto;
}
}
if (user->event == 0) {
int ret, flag = 0;
union T_primitives *p = (typeof(p)) user->ctlbuf;
user->ctrl.maxlen = user->ctlmax;
user->ctrl.len = 0;
user->ctrl.buf = user->ctlbuf;
user->data.maxlen = user->datmax;
user->data.len = 0;
user->data.buf = user->datbuf;
#ifndef CONFIG_XTI_IS_TYPELESS
switch (user->info.servtype) {
case T_CLTS:
if (user->state == T_IDLE)
user->data.maxlen = 0;
break;
case T_COTS_ORD:
if (user->state == T_OUTREL)
user->data.maxlen = 0;
case T_COTS:
if (user->state == T_DATAXFER)
user->data.maxlen = 0;
break;
default:
goto tsync;
}
#else
if ((user->state == T_IDLE && user->qlen == 0) || (user->state == T_OUTREL)
|| (user->state == T_DATAXFER))
user->data.maxlen = 0;
#endif
if ((ret = __xnet_t_getmsg(fd, &user->ctrl, &user->data, &flag)) < 0)
goto error;
if ((ret & MORECTL) || ((ret & MOREDATA) && user->data.maxlen > 0))
goto cleanup;
if (flag != 0 || flag == RS_HIPRI)
goto tsync;
switch (user->state) {
case T_UNINIT:
goto tsync;
case T_UNBND:
goto tsync;
case T_IDLE:
#ifndef CONFIG_XTI_IS_TYPELESS
switch (user->info.servtype) {
case T_COTS:
case T_COTS_ORD:
if (user->qlen > 0)
goto tincon;
goto tsync;
case T_CLTS:
if (user->ctrl.len == 0) {
if ((user->gflags = (ret & MOREDATA))) {
user->event = T_DATA;
return (T_DATA);
}
return (0);
}
switch ((user->prim = p->type)) {
case T_UNITDATA_IND:
user->event = T_DATA;
break;
case T_UDERROR_IND:
user->event = T_UDERR;
break;
default:
goto cleanup;
}
user->gflags = (ret & MOREDATA);
return (user->event);
default:
goto tsync;
}
#else
if (user->qlen > 0)
goto tincon;
if (user->ctrl.len == 0) {
if ((user->gflags = (ret & MOREDATA))) {
user->event = T_DATA;
return (T_DATA);
}
return (0);
}
switch ((user->prim = p->type)) {
case T_UNITDATA_IND:
user->event = T_DATA;
break;
case T_UDERROR_IND:
user->event = T_UDERR;
break;
default:
goto cleanup;
}
user->gflags = (ret & MOREDATA);
return (user->event);
#endif
case T_OUTCON:
switch ((user->prim = p->type)) {
case T_CONN_CON:
user->event = T_CONNECT;
break;
case T_DISCON_IND:
user->event = T_DISCONNECT;
break;
default:
goto cleanup;
}
user->gflags = 0;
return (user->event);
case T_INCON:
tincon:
switch ((user->prim = p->type)) {
case T_CONN_IND:
user->event = T_LISTEN;
break;
case T_DISCON_IND:
user->event = T_DISCONNECT;
break;
default:
goto cleanup;
}
user->gflags = 0;
return (user->event);
case T_DATAXFER:
case T_OUTREL:
if (user->ctrl.len == 0) {
if ((user->gflags = (ret & MOREDATA))) {
user->event = T_DATA;
return (T_DATA);
}
return (0);
}
switch ((user->prim = p->type)) {
case T_DATA_IND:
user->event = T_DATA;
break;
case T_EXDATA_IND:
user->event = T_EXDATA;
break;
case T_OPTDATA_IND:
user->event =
(p->optdata_ind.DATA_flag & T_ODF_EX) ? T_EXDATA : T_DATA;
break;
case T_ORDREL_IND:
if (ret & MOREDATA) {
user->data.maxlen = user->datmax;
user->data.len = 0;
user->data.buf = user->datbuf;
ret = __xnet_t_getmsg(fd, NULL, &user->data, &flag);
if (ret < 0)
goto error;
if (ret != 0)
goto cleanup;
if (flag != 0)
goto tsync;
}
user->event = (ret & MOREDATA) ? T_ORDRELDATA : T_ORDREL;
break;
case T_DISCON_IND:
if (ret & MOREDATA) {
user->data.maxlen = user->datmax;
user->data.len = 0;
user->data.buf = user->datbuf;
ret = __xnet_t_getmsg(fd, NULL, &user->data, &flag);
if (ret < 0)
goto error;
if (ret != 0)
goto cleanup;
if (flag != 0)
goto tsync;
}
user->event = T_DISCONNECT;
break;
default:
goto cleanup;
}
user->gflags = (ret & MOREDATA);
return (user->event);
case T_INREL:
switch ((user->prim = p->type)) {
case T_DISCON_IND:
user->event = T_DISCONNECT;
break;
default:
goto cleanup;
}
user->gflags = 0;
return (user->event);
default:
goto tsync;
}
cleanup:
user->ctrl.maxlen = user->ctlmax;
user->data.maxlen = user->datmax;
while (ret & (MORECTL | MOREDATA))
if ((ret = __xnet_t_getmsg(fd, &user->ctrl, &user->data, &flag)) < 0)
goto error;
goto tsync;
}
return (user->event);
tsync:
user->flags |= TUF_SYNC_REQUIRED;
goto error;
tproto:
t_errno = TPROTO;
goto error;
tsyserr:
t_errno = TSYSERR;
goto error;
error:
return (-1);
}
int
__xnet_t_look_r(int fd)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_look(fd);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_look_r,t_look@@XNET_1.0");
int
__xnet_t_open(const char *path, int oflag, struct t_info *info)
{
struct _t_user *user;
int err, fd;
t_errno = TSYSERR;
if (!(user = (struct _t_user *) malloc(sizeof(*user))))
goto enomem;
memset(user, 0, sizeof(*user));
user->ctlmax =
sizeof(union T_primitives) + _T_DEFAULT_ADDRLEN + _T_DEFAULT_ADDRLEN +
_T_DEFAULT_OPTLEN;
user->datmax = _T_DEFAULT_DATALEN;
if (!(user->ctlbuf = (char *) malloc(user->ctlmax)))
goto enobufs;
if (!(user->datbuf = (char *) malloc(user->datmax)))
goto enobufs;
if ((fd = open(path, oflag)) == -1)
goto badopen;
if (ioctl(fd, I_PUSH, "timod") != 0)
goto badioctl;
{
int i;
union {
struct T_capability_req req;
struct T_capability_ack ack;
} buf;
buf.req.PRIM_type = T_CAPABILITY_REQ;
buf.req.CAP_bits1 = TC1_INFO | TC1_ACCEPTOR_ID;
if (__xnet_t_strioctl(fd, TI_CAPABILITY, &buf, sizeof(buf)) != 0)
goto badioctl;
if ((buf.ack.CAP_bits1 & (TC1_INFO | TC1_ACCEPTOR_ID)) !=
(TC1_INFO | TC1_ACCEPTOR_ID))
goto badbits;
user->flags |= TUF_SYNC_REQUIRED;
for (i = 0; i < OPEN_MAX; i++)
if (_t_fds[i] && _t_fds[i]->token == buf.ack.ACCEPTOR_id) {
free(user);
user = _t_fds[i];
pthread_rwlock_destroy(&user->lock);
break;
}
user->fflags = oflag;
user->info.addr = buf.ack.INFO_ack.ADDR_size;
user->info.options = buf.ack.INFO_ack.OPT_size;
user->info.tsdu = buf.ack.INFO_ack.TSDU_size;
user->info.etsdu = buf.ack.INFO_ack.ETSDU_size;
user->info.connect = buf.ack.INFO_ack.CDATA_size;
user->info.discon = buf.ack.INFO_ack.DDATA_size;
user->info.servtype = buf.ack.INFO_ack.SERV_type;
user->info.flags = buf.ack.INFO_ack.PROVIDER_flag;
user->info.tidu = buf.ack.INFO_ack.TIDU_size;
user->token = buf.ack.ACCEPTOR_id;
user->refs++;
if (user->flags & TUF_SYNC_REQUIRED)
__xnet_u_setstate(user, buf.ack.INFO_ack.CURRENT_state);
pthread_rwlock_init(&user->lock, NULL);
_t_fds[fd] = user;
user->flags &= ~TUF_SYNC_REQUIRED;
if (info)
*info = user->info;
}
return (fd);
badbits:
t_errno = TPROTO;
badioctl:
err = errno;
close(fd);
free(user);
errno = err;
goto error;
badopen:
err = errno;
free(user);
errno = err;
goto error;
enobufs:
errno = ENOBUFS;
if (user->ctlbuf)
free(user->ctlbuf);
if (user->datbuf)
free(user->datbuf);
free(user);
goto error;
enomem:
errno = ENOMEM;
goto error;
error:
return (-1);
}
int
__xnet_t_open_r(const char *path, int oflag, struct t_info *info)
{
int err, ret = -1;
pthread_cleanup_push_defer_np(__xnet_list_unlock, NULL);
if ((err = __xnet_list_wrlock()) == 0) {
ret = __xnet_t_open(path, oflag, info);
__xnet_list_unlock(NULL);
} else {
t_errno = TSYSERR;
errno = err;
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_open_r,t_open@@XNET_1.0");
int
__xnet_t_optmgmt(int fd, const struct t_optmgmt *req, struct t_optmgmt *ret)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, -1, -1)))
goto error;
#ifdef DEBUG
if (!req)
goto einval;
if (req && (req->opt.len < 0 || (req->opt.len > 0 && !req->opt.buf)))
goto einval;
if (ret && (ret->opt.maxlen < 0 || (ret->opt.maxlen > 0 && !ret->opt.buf)))
goto einval;
#endif
if (req && req->opt.len > __xnet_u_max_options(user))
goto tbadopt;
{
size_t opt_len = (req && req->opt.len > 0) ? req->opt.len : 0;
size_t opt_max = min(__xnet_u_max_options(user), _T_DEFAULT_OPTLEN);
union {
struct {
struct T_optmgmt_req prim;
unsigned char opts[opt_len];
} req;
struct {
struct T_optmgmt_ack prim;
unsigned char opts[opt_max];
} ack;
} buf;
buf.req.prim.PRIM_type = T_OPTMGMT_REQ;
buf.req.prim.OPT_length = opt_len;
buf.req.prim.OPT_offset = opt_len ? sizeof(buf.req.prim) : 0;
buf.req.prim.MGMT_flags = req ? req->flags : 0;
if (opt_len)
memcpy(buf.req.opts, req->opt.buf, opt_len);
if (__xnet_t_strioctl(fd, TI_OPTMGMT, &buf, sizeof(buf)) != 0)
goto error;
if (ret) {
ret->flags = buf.ack.prim.MGMT_flags;
if (ret->opt.maxlen < buf.ack.prim.OPT_length)
goto tbufovflw;
if ((ret->opt.len = buf.ack.prim.OPT_length))
memcpy(ret->opt.buf, (char *) &buf + buf.ack.prim.OPT_offset,
ret->opt.len);
}
return (0);
}
tbadopt:
t_errno = TBADOPT;
goto error;
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbufovflw:
t_errno = TBUFOVFLW;
goto error;
error:
return (-1);
}
int
__xnet_t_optmgmt_r(int fd, const struct t_optmgmt *req, struct t_optmgmt *ret)
{
int rtv = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
rtv = __xnet_t_optmgmt(fd, req, ret);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (rtv);
}
__asm__(".symver __xnet_t_optmgmt_r,t_optmgmt@@XNET_1.0");
int
__xnet_t_rcv(int fd, char *buf, unsigned int nbytes, int *flags)
{
struct _t_user *user;
int copied = 0, event = 0, flag = 0, result;
if (!
(user =
__xnet_t_tstuser(fd, -1, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WIND_ORDREL)))
goto error;
if (nbytes == 0)
return (0);
#ifdef DEBUG
if (!flags || !buf)
goto einval;
#endif
{
struct strbuf data;
data.maxlen = nbytes;
data.len = 0;
data.buf = buf ? buf : NULL;
if ((result =
__xnet_t_getdata(fd, &data, (T_DATA | T_EXDATA))) & (T_DATA | T_EXDATA))
event = result;
for (;;) {
switch (result) {
case T_DATA:
if (event != T_DATA)
goto tlook;
flag = ((user->moresdu || user->moredat) ? T_MORE : 0);
break;
case T_EXDATA:
if (event != T_EXDATA)
goto tlook;
flag =
((user->moreedu || user->moreexp) ? T_MORE : 0) | T_EXPEDITED;
break;
case 0:
goto tnodata;
case -1:
goto error;
default:
goto tlook;
}
if ((copied += data.len) >= nbytes)
break;
if (!(flag & T_MORE)) {
__xnet_u_reset_event(user);
break;
}
data.maxlen -= data.len;
data.buf += data.len;
data.len = 0;
result = __xnet_t_getdata(fd, &data, event);
}
}
if (flags)
*flags = flag;
return (copied);
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tlook:
t_errno = TLOOK;
goto error;
tnodata:
t_errno = TNODATA;
goto error;
error:
if (copied) {
if (flags)
*flags = flag;
return (copied);
}
return (-1);
}
int
__xnet_t_rcv_r(int fd, char *buf, unsigned int nbytes, int *flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_rcv(fd, buf, nbytes, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcv_r,t_rcv@@XNET_1.0");
int
__xnet_t_rcvconnect(int fd, struct t_call *call)
{
struct _t_user *user;
union T_primitives *p;
if (!
(user =
__xnet_t_tstuser(fd, T_CONNECT, (1 << T_COTS) | (1 << T_COTS_ORD), TSF_WCON_CREQ)))
goto error;
#ifdef DEBUG
if (call && (call->addr.maxlen < 0 || (call->addr.maxlen > 0 && !call->addr.buf)))
goto einval;
if (call && (call->opt.maxlen < 0 || (call->opt.maxlen > 0 && !call->opt.buf)))
goto einval;
if (call && (call->udata.maxlen < 0 || (call->udata.maxlen > 0 && !call->udata.buf)))
goto einval;
#endif
p = (typeof(p)) user->ctlbuf;
switch (__xnet_t_getevent(fd)) {
case T_CONNECT:
{
__xnet_u_setstate_const(user, TS_DATA_XFER);
if (call) {
if (call->addr.maxlen && call->addr.maxlen < p->conn_con.RES_length)
goto tbufovflw;
if (call->opt.maxlen && call->opt.maxlen < p->conn_con.OPT_length)
goto tbufovflw;
if (call->udata.maxlen && call->udata.maxlen < user->data.len)
goto tbufovflw;
if (call->addr.maxlen && (call->addr.len = p->conn_con.RES_length))
memcpy(call->addr.buf, (char *) p + p->conn_con.RES_offset,
call->addr.len);
if (call->opt.maxlen && (call->opt.len = p->conn_con.OPT_length))
memcpy(call->opt.buf, (char *) p + p->conn_con.OPT_offset,
call->opt.len);
if (call->udata.maxlen && (call->udata.len = user->data.len))
memcpy(call->udata.buf, user->data.buf, call->udata.len);
}
__xnet_u_reset_event(user);
return (0);
}
case 0:
goto tnodata;
case -1:
goto error;
default:
goto tlook;
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tlook:
t_errno = TLOOK;
goto error;
tnodata:
t_errno = TNODATA;
goto error;
tbufovflw:
__xnet_u_reset_event(user);
t_errno = TBUFOVFLW;
goto error;
error:
return (-1);
}
int
__xnet_t_rcvconnect_r(int fd, struct t_call *call)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_rcvconnect(fd, call)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcvconnect_r,t_rcvconnect@@XNET_1.0");
int
__xnet_t_rcvdis(int fd, struct t_discon *discon)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, T_DISCONNECT, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WCON_CREQ | TSF_WIND_ORDREL |
TSF_WREQ_ORDREL | TSF_WRES_CIND)))
goto error;
if (user->state == T_INCON && user->ocnt < 1)
goto toutstate;
#ifdef DEBUG
if (discon
&& (discon->udata.maxlen < 0 || (discon->udata.maxlen > 0 && !discon->udata.buf)))
goto einval;
#endif
switch (__xnet_t_getevent(fd)) {
case T_DISCONNECT:
{
union T_primitives *p = (typeof(p)) user->ctrl.buf;
switch (user->state) {
case T_DATAXFER:
case T_OUTCON:
case T_OUTREL:
case T_INREL:
if (user->ocnt)
__xnet_u_setstate_const(user, TS_WRES_CIND);
else
__xnet_u_setstate_const(user, TS_IDLE);
break;
case T_INCON:
if (user->ocnt && --user->ocnt)
__xnet_u_setstate_const(user, TS_WRES_CIND);
else
__xnet_u_setstate_const(user, TS_IDLE);
break;
default:
goto toutstate;
}
if (discon) {
discon->reason = p->discon_ind.DISCON_reason;
discon->sequence = p->discon_ind.SEQ_number;
if (discon->udata.maxlen && discon->udata.maxlen < user->data.len)
goto tbufovflw;
if (discon->udata.maxlen && (discon->udata.len = user->data.len))
memcpy(discon->udata.buf, user->data.buf, discon->udata.len);
}
__xnet_u_reset_event(user);
return (0);
}
case 0:
goto tnodis;
case -1:
goto error;
default:
goto tlook;
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tlook:
t_errno = TLOOK;
goto error;
tnodis:
t_errno = TNODIS;
goto error;
tbufovflw:
__xnet_u_reset_event(user);
t_errno = TBUFOVFLW;
goto error;
toutstate:
t_errno = TOUTSTATE;
goto error;
error:
return (-1);
}
int
__xnet_t_rcvdis_r(int fd, struct t_discon *discon)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_rcvdis(fd, discon);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcvdis_r,t_rcvdis@@XNET_1.0");
int
__xnet_t_rcvleafchange(int fd, struct t_leaf_status *change)
{
#if defined HAVE_XTI_ATM_H
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD), TSF_DATA_XFER)))
goto error;
#ifdef DEBUG
if (!change)
goto einval;
#endif
{
struct {
struct t_opthdr hdr;
struct t_atm_leaf_ind leaf;
} opts;
struct t_optmgmt req, ret;
req.opt.maxlen = 0;
req.opt.len = sizeof(opts);
req.opt.buf = (char *) &opts;
req.flags = T_NEGOTIATE;
ret.opt.maxlen = sizeof(opts);
req.opt.len = 0;
req.opt.buf = (char *) &opts;
req.flags = 0;
opts.hdr.len = sizeof(opts);
opts.hdr.level = T_ATM_SIGNALLING;
opts.hdr.name = T_ATM_LEAF_IND;
opts.hdr.status = 0;
if (__xnet_t_optmgmt(fd, &req, &ret) == -1)
goto error;
if (ret.opt.flags == T_FAILURE)
goto tproto;
if (ret.opt.len < sizeof(opts) || opts.hdr.len < sizeof(opts))
goto tproto;
if (opts.hdr.status != T_SUCCESS)
goto tproto;
if (opts.hdr.level != T_ATM_SIGNALLING || opts.hdr.name != T_ATM_LEAF_IND)
goto tproto;
if (opts.leaf.status == T_LEAF_NOCHANGE)
goto tnodata;
if (change) {
change->leafid = opts.leaf.leaf_ID;
change->status = opts.leaf.status;
change->reason = opts.leaf.reason;
}
return (0);
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tproto:
t_errno = TPROTO;
goto error;
tnodata:
t_errno = TNODATA;
goto error;
error:
return (-1);
#else
t_errno = TNOTSUPPORT;
return (-1);
#endif
}
#pragma weak __xnet_t_rcvleafchange_r
int
__xnet_t_rcvleafchange_r(int fd, struct t_leaf_status *change)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_rcvleafchange(fd, change);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcvleafchange_r,t_rcvleafchange@@XNET_1.0");
int
__xnet_t_rcvrel(int fd)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, T_ORDREL, (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WIND_ORDREL)))
goto error;
switch (__xnet_t_getevent(fd)) {
case T_ORDREL:
{
user->event = 0;
if (user->state == T_DATAXFER)
__xnet_u_setstate_const(user, TS_WREQ_ORDREL);
if (user->state == T_OUTREL) {
if (user->ocnt)
__xnet_u_setstate_const(user, TS_WRES_CIND);
else
__xnet_u_setstate_const(user, TS_IDLE);
}
return (0);
}
case 0:
goto tnorel;
default:
goto tlook;
case -1:
goto error;
}
tlook:
t_errno = TLOOK;
goto error;
tnorel:
t_errno = TNOREL;
goto error;
error:
return (-1);
}
int
__xnet_t_rcvrel_r(int fd)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_rcvrel(fd)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcvrel_r,t_rcvrel@@XNET_1.0");
int
__xnet_t_rcvreldata(int fd, struct t_discon *discon)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, T_ORDREL, (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WIND_ORDREL)))
goto error;
#ifdef DEBUG
if (discon
&& (discon->udata.maxlen < 0 || (discon->udata.maxlen > 0 && !discon->udata.buf)))
goto einval;
#endif
switch (__xnet_t_getevent(fd)) {
case T_ORDREL:
{
union T_primitives *p = (typeof(p)) user->ctrl.buf;
if (user->state == T_DATAXFER)
__xnet_u_setstate_const(user, TS_WREQ_ORDREL);
if (user->state == T_OUTREL) {
if (user->ocnt)
__xnet_u_setstate_const(user, TS_WRES_CIND);
else
__xnet_u_setstate_const(user, TS_IDLE);
}
if (discon) {
discon->reason = 0;
discon->sequence = 0;
if (discon->udata.maxlen && discon->udata.maxlen < user->data.len)
goto tbufovflw;
if (discon->udata.maxlen && (discon->udata.len = user->data.len))
memcpy(discon->udata.buf, user->data.buf, discon->udata.len);
}
__xnet_u_reset_event(user);
return (0);
}
case 0:
goto tnorel;
case -1:
goto error;
default:
goto tlook;
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tlook:
t_errno = TLOOK;
goto error;
tnorel:
t_errno = TNOREL;
goto error;
tbufovflw:
__xnet_u_reset_event(user);
t_errno = TBUFOVFLW;
goto error;
error:
return (-1);
}
int
__xnet_t_rcvreldata_r(int fd, struct t_discon *discon)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_rcvreldata(fd, discon)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcvreldata_r,t_rcvreldata@@XNET_1.0");
int
__xnet_t_rcvopt(int fd, struct t_unitdata *optdata, int *flags)
{
struct _t_user *user;
int copied = 0;
if (!(user = __xnet_t_tstuser(fd, -1, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WIND_ORDREL)))
goto error;
#ifdef DEBUG
if (!optdata)
goto einval;
if (!flags)
goto einval;
#endif
if (!optdata)
return (0);
switch (__xnet_t_getevent(fd)) {
case T_DATA:
case T_EXDATA:
{
union T_primitives *p = (typeof(p)) user->ctrl.buf;
switch (user->prim) {
case T_DATA_IND:
if (optdata->addr.maxlen >= 0)
optdata->addr.len = 0;
if (optdata->opt.maxlen >= 0)
optdata->opt.len = 0;
if (optdata->udata.maxlen
&& (optdata->udata.maxlen =
min(optdata->udata.maxlen, user->data.len))) {
memcpy(optdata->udata.buf, user->data.buf, optdata->udata.len);
user->data.len -= optdata->udata.len;
user->data.buf += optdata->udata.len;
}
if (flags)
*flags |= (user->moresdu || user->moredat
|| user->data.len > 0) ? T_MORE : 0;
break;
case T_EXDATA_IND:
if (optdata->addr.maxlen >= 0)
optdata->addr.len = 0;
if (optdata->opt.maxlen >= 0)
optdata->opt.len = 0;
if (optdata->udata.maxlen
&& (optdata->udata.len = min(optdata->udata.maxlen, user->data.len))) {
memcpy(optdata->udata.buf, user->data.buf, optdata->udata.len);
user->data.len -= optdata->udata.len;
user->data.buf += optdata->udata.len;
}
if (flags)
*flags |= (user->moreedu || user->moreexp
|| user->data.len >
0) ? T_MORE | T_EXPEDITED : T_EXPEDITED;
break;
case T_OPTDATA_IND:
if (optdata->addr.maxlen >= 0)
optdata->addr.len = 0;
if (optdata->opt.maxlen && optdata->opt.maxlen < p->optdata_ind.OPT_length)
goto tbufovflw;
if (optdata->opt.maxlen && (optdata->opt.len = p->optdata_ind.OPT_length))
memcpy(optdata->opt.buf, (char *) p + p->optdata_ind.OPT_offset,
optdata->opt.len);
if (optdata->udata.maxlen
&& (optdata->udata.len = min(optdata->udata.maxlen, user->data.len))) {
memcpy(optdata->udata.buf, user->data.buf, optdata->udata.len);
user->data.len -= optdata->udata.len;
user->data.buf += optdata->udata.len;
}
if (p->optdata_ind.DATA_flag & T_ODF_EX) {
if (flags)
*flags |= (user->moreedu || user->moreexp
|| user->data.len >
0) ? T_MORE | T_EXPEDITED : T_EXPEDITED;
} else {
if (flags)
*flags |= (user->moresdu || user->moredat
|| user->data.len > 0) ? T_MORE : 0;
}
break;
default:
goto tlook;
}
__xnet_u_reset_event(user);
return (0);
}
case 0:
goto tnodata;
case -1:
goto error;
default:
goto tlook;
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tlook:
t_errno = TLOOK;
goto error;
tnodata:
t_errno = TNODATA;
goto error;
tbufovflw:
__xnet_u_reset_event(user);
t_errno = TBUFOVFLW;
goto error;
error:
if (!copied)
return (-1);
return (copied);
}
int
__xnet_t_rcvopt_r(int fd, struct t_unitdata *optdata, int *flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_rcvopt(fd, optdata, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcvopt_r,t_rcvopt@@XNET_1.0");
__hot int
__xnet_t_rcvudata(int fd, struct t_unitdata *unitdata, int *flags)
{
struct _t_user *user;
int copied = 0, flag = 0, result;
if (unlikely(!(user = __xnet_t_tstuser(fd, T_DATA, (1 << T_CLTS), TSF_IDLE))))
goto error;
#ifdef DEBUG
if (!unitdata)
goto einval;
if (!flags)
goto einval;
#endif
if (unlikely(!unitdata))
goto done;
{
struct strbuf data;
data.maxlen = likely(unitdata->udata.maxlen > 0)
? unitdata->udata.maxlen : 0;
data.len = 0;
data.buf = unitdata->udata.buf;
if (likely((result = __xnet_t_getdata(fd, &data, T_DATA)) == T_DATA)) {
union T_primitives *p = (typeof(p)) user->ctrl.buf;
if (likely(user->prim == T_UNITDATA_IND)) {
if (unlikely(unitdata->addr.maxlen)
&& unlikely(unitdata->addr.maxlen < p->unitdata_ind.SRC_length))
goto tbufovflw;
if (unlikely(unitdata->opt.maxlen)
&& unlikely(unitdata->opt.maxlen < p->unitdata_ind.OPT_length))
goto tbufovflw;
if (unlikely(unitdata->addr.maxlen)
&& (unitdata->addr.len = p->unitdata_ind.SRC_length))
memcpy(unitdata->addr.buf,
(char *) p + p->unitdata_ind.SRC_offset,
unitdata->addr.len);
if (unlikely(unitdata->opt.maxlen)
&& (unitdata->opt.len = p->unitdata_ind.OPT_length))
memcpy(unitdata->opt.buf,
(char *) p + p->unitdata_ind.OPT_offset,
unitdata->opt.len);
} else {
unitdata->addr.len = 0;
unitdata->opt.len = 0;
}
}
for (;;) {
if (likely(result == T_DATA))
flag = (user->moresdu || user->moredat) ? T_MORE : 0;
else if (result == 0)
goto tnodata;
else if (result == -1)
goto error;
else
goto tlook;
if (likely((copied += data.len) >= unitdata->udata.maxlen))
break;
if (likely(!(flag & T_MORE))) {
__xnet_u_reset_event(user);
break;
}
data.maxlen -= data.len;
data.len = 0;
data.buf += data.len;
result = __xnet_t_getdata(fd, &data, T_DATA);
}
}
if (flags)
*flags = flag;
unitdata->udata.len = copied;
done:
return (0);
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tlook:
t_errno = TLOOK;
goto error;
tnodata:
t_errno = TNODATA;
goto error;
tbufovflw:
__xnet_u_reset_event(user);
t_errno = TBUFOVFLW;
goto error;
error:
if (flags)
*flags = flag;
unitdata->udata.len = copied;
return (-1);
}
__hot int
__xnet_t_rcvudata_r(int fd, struct t_unitdata *unitdata, int *flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_rcvudata(fd, unitdata, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcvudata_r,t_rcvudata@@XNET_1.0");
int
__xnet_t_rcvuderr(int fd, struct t_uderr *uderr)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, T_UDERR, (1 << T_CLTS), TSF_IDLE)))
goto error;
#ifdef DEBUG
if (uderr && (uderr->addr.maxlen < 0 || (uderr->addr.maxlen > 0 && !uderr->addr.buf)))
goto einval;
if (uderr && (uderr->opt.maxlen < 0 || (uderr->opt.maxlen > 0 && !uderr->opt.buf)))
goto einval;
#endif
switch (__xnet_t_getevent(fd)) {
case T_UDERR:
{
union T_primitives *p = (typeof(p)) user->ctrl.buf;
if (uderr) {
uderr->error = p->uderror_ind.ERROR_type;
if (uderr->addr.maxlen && uderr->addr.maxlen < p->uderror_ind.DEST_length)
goto tbufovflw;
if (uderr->opt.maxlen && uderr->opt.maxlen < p->uderror_ind.OPT_length)
goto tbufovflw;
if (uderr->addr.maxlen && (uderr->addr.len = p->uderror_ind.DEST_length))
memcpy(uderr->addr.buf, (char *) p + p->uderror_ind.DEST_offset,
uderr->addr.len);
if (uderr->opt.maxlen && (uderr->opt.len = p->uderror_ind.OPT_length))
memcpy(uderr->opt.buf, (char *) p + p->uderror_ind.OPT_offset,
uderr->opt.len);
}
__xnet_u_reset_event(user);
return (0);
}
case 0:
goto tnouderr;
case -1:
goto error;
default:
goto tlook;
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbufovflw:
__xnet_u_reset_event(user);
t_errno = TBUFOVFLW;
goto error;
tnouderr:
t_errno = TNOUDERR;
goto error;
tlook:
t_errno = TLOOK;
goto error;
error:
return (-1);
}
int
__xnet_t_rcvuderr_r(int fd, struct t_uderr *uderr)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_rcvuderr(fd, uderr);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcvuderr_r,t_rcvuderr@@XNET_1.0");
int
__xnet_t_rcvv(int fd, struct t_iovec *iov, unsigned int iovcount, int *flags)
{
struct _t_user *user;
int copied = 0, nbytes, n = 0, event = 0, flag = 0, result;
if (!(user = __xnet_t_tstuser(fd, -1, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WIND_ORDREL)))
goto error;
#ifdef DEBUG
if (!flags)
goto einval;
if (!iov)
goto einval;
#endif
if (!iov)
return (0);
for (nbytes = 0, n = 0; n < iovcount; nbytes += iov[n].iov_len, n++) ;
if (iovcount == 0 || iovcount > _T_IOV_MAX)
goto tbaddata;
{
struct strbuf data;
data.maxlen = iov[0].iov_len;
data.len = 0;
data.buf = iov[0].iov_base;
if ((result =
__xnet_t_getdata(fd, &data, (T_DATA | T_EXDATA))) & (T_DATA | T_EXDATA))
event = result;
for (n = 0;;) {
switch (result) {
case T_DATA:
if (event != T_DATA)
goto tlook;
flag = ((user->moresdu || user->moredat) ? T_MORE : 0);
break;
case T_EXDATA:
if (event != T_EXDATA)
goto tlook;
flag =
((user->moreedu || user->moreexp) ? T_MORE : 0) | T_EXPEDITED;
break;
case 0:
goto tnodata;
case -1:
goto error;
default:
goto tlook;
}
if ((copied += data.len) >= nbytes)
break;
if (!(flag & T_MORE)) {
__xnet_u_reset_event(user);
break;
}
if (data.maxlen <= data.len) {
if (++n >= iovcount)
break;
data.maxlen = iov[n].iov_len;
data.buf = iov[n].iov_base;
data.len = 0;
} else {
data.maxlen -= data.len;
data.buf += data.len;
data.len = 0;
}
result = __xnet_t_getdata(fd, &data, event);
}
}
if (flags)
*flags = flag;
return (copied);
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tlook:
t_errno = TLOOK;
goto error;
tnodata:
t_errno = TNODATA;
goto error;
tbaddata:
t_errno = TBADDATA;
goto error;
error:
if (!copied)
return (-1);
if (flags)
*flags = flag;
return (copied);
}
int
__xnet_t_rcvv_r(int fd, struct t_iovec *iov, unsigned int iovcount, int *flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_rcvv(fd, iov, iovcount, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_rcvv_r,t_rcvv@@XNET_1.0");
int
__xnet_t_rcvvudata(int fd, struct t_unitdata *unitdata, struct t_iovec *iov, unsigned int iovcount,
int *flags)
{
struct _t_user *user;
int copied = 0, nbytes, n = 0, flag = 0, result;
if (!(user = __xnet_t_tstuser(fd, T_DATA, (1 << T_CLTS), TSF_IDLE)))
goto error;
for (nbytes = 0, n = 0; n < iovcount; nbytes += iov[n].iov_len, n++) ;
if (iovcount == 0 || iovcount > _T_IOV_MAX)
goto tbaddata;
#ifdef DEBUG
if (!unitdata)
goto einval;
if (!flags)
goto einval;
#endif
{
struct strbuf data;
data.maxlen = iov[0].iov_len;
data.len = 0;
data.buf = iov[0].iov_base;
if ((result = __xnet_t_getdata(fd, &data, T_DATA)) == T_DATA) {
union T_primitives *p = (typeof(p)) user->ctrl.buf;
switch (user->prim) {
case T_UNITDATA_IND:
if (unitdata) {
if (unitdata->addr.maxlen
&& unitdata->addr.maxlen < p->unitdata_ind.SRC_length)
goto tbufovflw;
if (unitdata->opt.maxlen
&& unitdata->opt.maxlen < p->unitdata_ind.OPT_length)
goto tbufovflw;
if (unitdata->addr.maxlen
&& (unitdata->addr.len = p->unitdata_ind.OPT_length))
memcpy(unitdata->addr.buf,
(char *) p + p->unitdata_ind.SRC_offset,
unitdata->addr.len);
if (unitdata->opt.maxlen
&& (unitdata->opt.len = p->unitdata_ind.OPT_length))
memcpy(unitdata->opt.buf,
(char *) p + p->unitdata_ind.OPT_offset,
unitdata->opt.len);
}
break;
default:
if (unitdata) {
unitdata->addr.len = 0;
unitdata->opt.len = 0;
}
break;
}
}
for (;;) {
switch (result) {
case T_DATA:
flag = (user->moresdu || user->moredat) ? T_MORE : 0;
break;
case 0:
goto tnodata;
case -1:
goto error;
default:
goto tlook;
}
if ((copied += data.len) >= nbytes)
break;
if (!(flag & T_MORE)) {
__xnet_u_reset_event(user);
break;
}
if (data.maxlen <= data.len) {
if (++n >= iovcount)
break;
data.maxlen = iov[n].iov_len;
data.len = 0;
data.buf = iov[n].iov_base;
} else {
data.maxlen -= data.len;
data.len = 0;
data.buf += data.len;
}
result = __xnet_t_getdata(fd, &data, T_DATA);
}
}
if (flags)
*flags = flag;
if (unitdata)
unitdata->udata.len = copied;
return (0);
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tlook:
t_errno = TLOOK;
goto error;
tnodata:
t_errno = TNODATA;
goto error;
tbufovflw:
__xnet_u_reset_event(user);
t_errno = TBUFOVFLW;
goto error;
tbaddata:
t_errno = TBADDATA;
goto error;
error:
if (flags)
*flags = flag;
if (unitdata)
unitdata->udata.len = copied;
return (-1);
}
int __xnet_t_rcvvopt(int fd, struct t_unitdata *unitdata, struct t_iovec *iov, unsigned int
iovcount, int *flags)
__attribute__((alias("__xnet_t_rcvvudata")));
int
__xnet_t_rcvvudata_r(int fd, struct t_unitdata *unitdata, struct t_iovec *iov,
unsigned int iovcount, int *flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_rcvvudata(fd, unitdata, iov, iovcount, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
int __xnet_t_rcvvopt_r(int fd, struct t_unitdata *unitdata, struct t_iovec *iov, unsigned int
iovcount, int *flags)
__attribute__((alias("__xnet_t_rcvvudata_r")));
__asm__(".symver __xnet_t_rcvvudata_r,t_rcvvudata@@XNET_1.0");
__asm__(".symver __xnet_t_rcvvopt_r,t_rcvvopt@@XNET_1.0");
int
__xnet_t_removeleaf(int fd, int leafid, int reason)
{
#if defined HAVE_XTI_ATM_H
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD), TSF_DATA_XFER)))
goto error;
{
struct {
struct t_opthdr hdr;
struct t_atm_drop_leaf leaf;
} opts;
struct t_optmgmt req, ret;
req.opt.maxlen = 0;
req.opt.len = sizeof(opts);
req.opt.buf = (char *) &opts;
req.flags = T_CURRENT;
ret.opt.maxlen = sizeof(opts);
ret.opt.len = 0;
ret.opt.buf = (char *) &opts;
ret.flags = 0;
opts.hdr.len = sizeof(opts);
opts.hdr.level = T_ATM_SIGNALLING;
opts.hdr.name = T_ATM_DROP_LEAF;
opts.hdr.status = 0;
opts.leaf.leaf_ID = leafid;
opts.leaf.reason = reason;
if (__xnet_t_optmgmt(fd, &req, &ret) == -1)
goto error;
if (ret.opt.flags == T_FAILURE)
goto tproto;
if (ret.opt.len < sizeof(opts) || opts.hdr.len < sizeof(opts))
goto tproto;
if (opts.hdr.status != T_SUCCESS)
goto tproto;
if (opts.hdr.level != T_ATM_SIGNALLING || opts.hdr.name != T_ATM_DROP_LEAF)
goto tproto;
goto tnodata;
}
tnodata:
t_errno = TNODATA;
goto error;
error:
return (-1);
#else
t_errno = TNOTSUPPORT;
return (-1);
#endif
}
#pragma weak __xnet_t_removeleaf_r
int
__xnet_t_removeleaf_r(int fd, int leafid, int reason)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_removeleaf(fd, leafid, reason);
__xnet_t_putuser(&fd);
}
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_removeleaf_r,t_removeleaf@@XNET_1.0");
int
__xnet_t_snd(int fd, char *buf, unsigned int nbytes, int flags)
{
struct _t_user *user;
int written = 0;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WREQ_ORDREL)))
goto error;
if (__xnet_t_look(fd) > 0)
goto tlook;
#ifdef DEBUG
if (!buf)
goto einval;
#endif
if (nbytes == 0 && !(user->info.flags & T_SNDZERO))
goto tbaddata;
if (nbytes > ((flags & T_EXPEDITED) ? __xnet_u_max_etsdu(user) : __xnet_u_max_tsdu(user)))
goto tbaddata;
if (!buf)
return (0);
{
int band = (flags & T_EXPEDITED) ? 1 : 0;
struct T_exdata_req prim;
struct strbuf ctrl, data;
ctrl.maxlen = 0;
ctrl.len = sizeof(prim);
ctrl.buf = (char *) &prim;
data.maxlen = 0;
data.len = nbytes;
data.buf = buf;
prim.PRIM_type = (flags & T_EXPEDITED) ? T_EXDATA_REQ : T_DATA_REQ;
do {
data.len = min(__xnet_u_max_tidu(user), nbytes - written);
data.buf = buf + written;
prim.MORE_flag = (written + data.len < nbytes) || (flags & T_MORE);
if (__xnet_t_putpmsg(fd, &ctrl, &data, band, MSG_BAND) == -1)
goto error;
written += data.len;
} while (written < nbytes);
return (written);
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbaddata:
t_errno = TBADDATA;
goto error;
tlook:
t_errno = TLOOK;
goto error;
error:
if (!written) {
if (t_errno != TLOOK && __xnet_t_look(fd))
goto tlook;
return (-1);
}
return (written);
}
int
__xnet_t_snd_r(int fd, char *buf, unsigned int nbytes, int flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_snd(fd, buf, nbytes, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_snd_r,t_snd@@XNET_1.0");
int
__xnet_t_snddis(int fd, const struct t_call *call)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_WCON_CREQ | TSF_WRES_CIND | TSF_DATA_XFER |
TSF_WIND_ORDREL | TSF_WREQ_ORDREL)))
goto error;
if (__xnet_t_look(fd) > 0)
goto tlook;
if (user->state == T_INREL && (!call || (user->ocnt > 1 && !call->sequence)))
goto tbadseq;
#ifdef DEBUG
if (call && (call->udata.len < 0 || (call->udata.len > 0 && !call->udata.buf)))
goto einval;
#endif
if (call && call->udata.len > __xnet_u_max_discon(user))
goto tbaddata;
{
size_t dat_len = (call && call->udata.len > 0) ? call->udata.len : 0;
struct {
struct T_discon_req prim;
unsigned char udata[dat_len];
} req;
req.prim.PRIM_type = T_DISCON_REQ;
req.prim.SEQ_number = call ? call->sequence : 0;
if (dat_len)
memcpy(req.udata, call->udata.buf, dat_len);
switch (user->state) {
case T_DATAXFER:
case T_OUTCON:
case T_OUTREL:
case T_INREL:
if (__xnet_t_strioctl(fd, TI_SETPEERNAME, &req, sizeof(req)) != 0)
goto error;
if (user->ocnt)
__xnet_u_setstate_const(user, TS_WRES_CIND);
else
__xnet_u_setstate_const(user, TS_IDLE);
return (0);
case T_INCON:
if (__xnet_t_strioctl(fd, TI_SETMYNAME, &req, sizeof(req)) != 0)
goto error;
if (user->ocnt > 0 && --user->ocnt)
__xnet_u_setstate_const(user, TS_WRES_CIND);
else
__xnet_u_setstate_const(user, TS_IDLE);
return (0);
default:
goto toutstate;
}
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbaddata:
t_errno = TBADDATA;
goto error;
tbadseq:
t_errno = TBADSEQ;
goto error;
toutstate:
t_errno = TOUTSTATE;
goto error;
tlook:
t_errno = TLOOK;
goto error;
error:
if (t_errno != TLOOK && __xnet_t_look(fd) > 0)
goto tlook;
return (-1);
}
int
__xnet_t_snddis_r(int fd, const struct t_call *call)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
ret = __xnet_t_snddis(fd, call);
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_snddis_r,t_snddis@@XNET_1.0");
int
__xnet_t_sndrel(int fd)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS_ORD), TSF_DATA_XFER | TSF_WREQ_ORDREL)))
goto error;
if (__xnet_t_look(fd) > 0)
goto tlook;
{
struct T_ordrel_req prim;
struct strbuf ctrl;
prim.PRIM_type = T_ORDREL_REQ;
ctrl.maxlen = sizeof(prim);
ctrl.len = sizeof(prim);
ctrl.buf = (char *) &prim;
if (__xnet_t_putmsg(fd, &ctrl, NULL, 0) != 0)
goto error;
switch (user->state) {
case T_DATAXFER:
__xnet_u_setstate_const(user, TS_WIND_ORDREL);
break;
case T_INREL:
if (user->ocnt)
__xnet_u_setstate_const(user, TS_WRES_CIND);
else
__xnet_u_setstate_const(user, TS_IDLE);
break;
}
return (0);
}
tlook:
t_errno = TLOOK;
goto error;
error:
if (t_errno != TLOOK && __xnet_t_look(fd) > 0)
goto tlook;
return (-1);
}
int
__xnet_t_sndrel_r(int fd)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_sndrel(fd)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_sndrel_r,t_sndrel@@XNET_1.0");
int
__xnet_t_sndreldata(int fd, struct t_discon *discon)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS_ORD), TSF_DATA_XFER | TSF_WREQ_ORDREL)))
goto error;
if (__xnet_t_look(fd) > 0)
goto tlook;
if (!(user->info.flags & T_ORDRELDATA))
goto tnotsupport;
#ifdef DEBUG
if (discon && (discon->udata.len < 0 || (discon->udata.len > 0 && !discon->udata.buf)))
goto einval;
#endif
if (discon && discon->udata.len > __xnet_u_max_discon(user))
goto tbaddata;
{
struct T_ordrel_req prim;
struct strbuf ctrl, data;
prim.PRIM_type = T_ORDREL_REQ;
ctrl.maxlen = sizeof(prim);
ctrl.len = sizeof(prim);
ctrl.buf = (char *) &prim;
data.maxlen = discon ? discon->udata.maxlen : 0;
data.len = discon ? discon->udata.len : 0;
data.buf = discon ? discon->udata.buf : NULL;
if (__xnet_t_putmsg(fd, &ctrl, &data, 0) != 0)
goto error;
switch (user->state) {
case T_DATAXFER:
__xnet_u_setstate_const(user, TS_WIND_ORDREL);
break;
case T_INREL:
if (user->ocnt)
__xnet_u_setstate_const(user, TS_WRES_CIND);
else
__xnet_u_setstate_const(user, TS_IDLE);
break;
}
return (0);
}
tbaddata:
t_errno = TBADDATA;
goto error;
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tnotsupport:
t_errno = TNOTSUPPORT;
goto error;
tlook:
t_errno = TLOOK;
goto error;
error:
if (t_errno != TLOOK && __xnet_t_look(fd) > 0)
goto tlook;
return (-1);
}
int
__xnet_t_sndreldata_r(int fd, struct t_discon *discon)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_sndreldata(fd, discon)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_sndreldata_r,t_sndreldata@@XNET_1.0");
int
__xnet_t_sndopt(int fd, const struct t_unitdata *optdata, int flags)
{
struct _t_user *user;
int written = 0;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WIND_ORDREL)))
goto error;
#ifdef DEBUG
if (!optdata)
goto einval;
#endif
if (optdata && optdata->opt.len > __xnet_u_max_options(user))
goto tbadopt;
if (optdata && optdata->udata.len > __xnet_u_max_tsdu(user))
goto tbaddata;
if (optdata && optdata->udata.len == 0 && !(user->info.flags & T_SNDZERO))
goto tbaddata;
{
int band = (flags & T_EXPEDITED) ? 1 : 0;
size_t opt_len = (optdata && optdata->opt.len) > 0 ? optdata->opt.len : 0;
size_t dat_len = (optdata && optdata->udata.len) > 0 ? optdata->udata.len : 0;
struct {
struct T_optdata_req prim;
unsigned char opt[opt_len];
} req;
struct strbuf ctrl, data;
ctrl.maxlen = 0;
ctrl.len = sizeof(req);
ctrl.buf = (char *) &req;
data.maxlen = 0;
data.len = dat_len;
data.buf = optdata ? optdata->udata.buf : NULL;
req.prim.PRIM_type = T_OPTDATA_REQ;
req.prim.DATA_flag =
((flags & T_EXPEDITED) ? T_ODF_EX : 0) | ((flags & T_MORE) ? T_ODF_MORE : 0);
req.prim.OPT_length = opt_len;
req.prim.OPT_offset = opt_len ? sizeof(req.prim) : 0;
if (opt_len)
memcpy(req.opt, optdata->opt.buf, opt_len);
while (written < dat_len) {
data.len = min(__xnet_u_max_tidu(user), dat_len - written);
data.buf = optdata->udata.buf + written;
req.prim.DATA_flag = (((flags & T_EXPEDITED)) ? T_ODF_EX : 0)
| (((flags & T_MORE) || (written + data.len < dat_len)) ? T_ODF_MORE :
0);
if (__xnet_t_putpmsg(fd, &ctrl, &data, band, MSG_BAND))
goto error;
written += data.len;
}
return (written);
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbadopt:
t_errno = TBADOPT;
goto error;
tbaddata:
t_errno = TBADDATA;
goto error;
error:
if (!written)
return (-1);
return (written);
}
int
__xnet_t_sndopt_r(int fd, const struct t_unitdata *optdata, int flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_sndopt(fd, optdata, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_sndopt_r,t_sndopt@@XNET_1.0");
int
__xnet_t_sndvopt(int fd, const struct t_unitdata *optdata, const struct t_iovec *iov,
unsigned int iovcount, int flags)
{
struct _t_user *user;
int written = 0, nbytes, i;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WREQ_ORDREL)))
goto error;
#ifdef DEBUG
if (!iov)
goto einval;
#endif
for (nbytes = 0, i = 0; i < iovcount; nbytes += iov[i].iov_len, i++) ;
if (nbytes == 0 && !(user->info.flags & T_SNDZERO))
goto tbaddata;
if (nbytes > ((flags & T_EXPEDITED) ? __xnet_u_max_etsdu(user) : __xnet_u_max_tsdu(user)))
goto tbaddata;
{
size_t opt_len = (optdata && optdata->opt.len > 0) ? optdata->opt.len : 0;
int band = (flags & T_EXPEDITED) ? 1 : 0;
int n = 0, partial = 0;
struct {
struct T_optdata_req prim;
unsigned char opt[opt_len];
} req;
struct strbuf ctrl, data;
ctrl.maxlen = 0;
ctrl.len = sizeof(req);
ctrl.buf = (char *) &req;
data.maxlen = 0;
data.len = nbytes;
data.buf = optdata ? optdata->udata.buf : NULL;
req.prim.PRIM_type = T_OPTDATA_REQ;
req.prim.OPT_length = opt_len;
req.prim.OPT_offset = opt_len ? sizeof(req.prim) : 0;
if (opt_len)
memcpy(req.opt, optdata->opt.buf, opt_len);
do {
do {
data.len = min(__xnet_u_max_tidu(user), iov[n].iov_len - partial);
data.buf = iov[n].iov_base + partial;
req.prim.DATA_flag = (((flags & T_EXPEDITED)) ? T_ODF_EX : 0) |
(((flags & T_MORE)
|| (written + data.len < nbytes)) ? T_ODF_MORE : 0);
if (__xnet_t_putpmsg(fd, &ctrl, &data, band, MSG_BAND) == -1)
goto error;
partial += data.len;
written += data.len;
} while (partial < iov[n].iov_len);
n++;
partial = 0;
} while (written < nbytes && n < iovcount);
return (written);
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbaddata:
t_errno = TBADDATA;
goto error;
error:
if (!written)
return (-1);
return (written);
}
int
__xnet_t_sndvopt_r(int fd, const struct t_unitdata *optdata, const struct t_iovec *iov,
unsigned int iovcount, int flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_sndvopt(fd, optdata, iov, iovcount, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_sndvopt_r,t_sndvopt@@XNET_1.0");
__hot int
__xnet_t_sndudata(int fd, const struct t_unitdata *unitdata)
{
struct _t_user *user;
if (!(user = __xnet_t_tstuser(fd, T_DATA, (1 << T_CLTS), TSF_IDLE)))
goto error;
#if 1
if ((__xnet_t_look(fd) & ~T_DATA) > 0)
goto tlook;
#endif
#ifdef DEBUG
if (unlikely(!unitdata))
goto einval;
if (unlikely(unitdata->addr.len < 0 || (unitdata->addr.len > 0 && !unitdata->addr.buf)))
goto einval;
if (unlikely(unitdata->opt.len < 0 || (unitdata->opt.len > 0 && !unitdata->opt.buf)))
goto einval;
if (unlikely(unitdata->udata.len < 0 || (unitdata->udata.len > 0 && !unitdata->udata.buf)))
goto einval;
#endif
if (likely(unitdata)) {
if (unlikely(unitdata->addr.len > __xnet_u_max_addr(user)))
goto tbadaddr;
if (unlikely(unitdata->opt.len > __xnet_u_max_options(user)))
goto tbadopt;
if (unlikely(unitdata->udata.len > __xnet_u_max_tsdu(user)))
goto tbaddata;
if (unlikely(unitdata->udata.len > __xnet_u_max_tidu(user)))
goto tbaddata;
if (unlikely(unitdata->udata.len == 0 && !(user->info.flags & T_SNDZERO)))
goto tbaddata;
} else {
if (unlikely(!(user->info.flags & T_SNDZERO)))
goto tbaddata;
}
{
size_t add_len = (likely(unitdata)
&& likely(unitdata->addr.len > 0)) ? unitdata->addr.len : 0;
size_t opt_len = (likely(unitdata)
&& unlikely(unitdata->opt.len > 0)) ? unitdata->opt.len : 0;
struct {
struct T_unitdata_req prim;
unsigned char addr[add_len];
unsigned char opt[opt_len];
} req;
struct strbuf ctrl, data;
ctrl.maxlen = sizeof(req);
ctrl.len = sizeof(req);
ctrl.buf = (char *) &req;
if (likely(unitdata)) {
data.maxlen = unitdata->udata.maxlen;
data.len = unitdata->udata.len;
data.buf = unitdata->udata.buf;
} else {
data.maxlen = 0;
data.len = 0;
data.buf = NULL;
}
req.prim.PRIM_type = T_UNITDATA_REQ;
req.prim.DEST_length = add_len;
req.prim.DEST_offset = likely(add_len) ? sizeof(req.prim) : 0;
req.prim.OPT_length = opt_len;
req.prim.OPT_offset = unlikely(opt_len) ? sizeof(req.prim) + add_len : 0;
if (likely(add_len))
memcpy(req.addr, unitdata->addr.buf, add_len);
if (unlikely(opt_len))
memcpy(req.addr + add_len, unitdata->opt.buf, opt_len);
if (unlikely(__xnet_t_putmsg(fd, &ctrl, &data, 0)))
goto error;
return (0);
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbaddata:
t_errno = TBADDATA;
goto error;
tbadopt:
t_errno = TBADOPT;
goto error;
tbadaddr:
t_errno = TBADADDR;
goto error;
tlook:
t_errno = TLOOK;
goto error;
error:
if (t_errno != TLOOK && (__xnet_t_look(fd) & ~T_DATA) > 0)
goto tlook;
return (-1);
}
__hot int
__xnet_t_sndudata_r(int fd, const struct t_unitdata *unitdata)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_sndudata(fd, unitdata)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_sndudata_r,t_sndudata@@XNET_1.0");
int
__xnet_t_sndv(int fd, const struct t_iovec *iov, unsigned int iovcount, int flags)
{
struct _t_user *user;
int written = 0, nbytes, i;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WREQ_ORDREL)))
goto error;
if (__xnet_t_look(fd) > 0)
goto tlook;
#ifdef DEBUG
if (!iov)
goto einval;
#endif
if (iovcount == 0 || iovcount > _T_IOV_MAX)
goto tbaddata;
for (nbytes = 0, i = 0; i < iovcount; nbytes += iov[i].iov_len, i++) ;
if (nbytes == 0 && !(user->info.flags & T_SNDZERO))
goto tbaddata;
if (nbytes > ((flags & T_EXPEDITED) ? __xnet_u_max_etsdu(user) : __xnet_u_max_tsdu(user)))
goto tbaddata;
{
int band = (flags & T_EXPEDITED) ? 1 : 0;
int n = 0, partial = 0;
struct T_exdata_req prim;
struct strbuf ctrl, data;
ctrl.maxlen = 0;
ctrl.len = sizeof(prim);
ctrl.buf = (char *) &prim;
data.maxlen = 0;
data.len = nbytes;
data.buf = NULL;
prim.PRIM_type = (flags & T_EXPEDITED) ? T_EXDATA_REQ : T_DATA_REQ;
do {
do {
data.len = min(__xnet_u_max_tidu(user), iov[n].iov_len - partial);
data.buf = iov[n].iov_base + partial;
prim.MORE_flag = (written + data.len < nbytes) || (flags & T_MORE);
if (__xnet_t_putpmsg(fd, &ctrl, &data, band, MSG_BAND) == -1)
goto error;
partial += data.len;
written += data.len;
} while (partial < iov[n].iov_len);
n++;
partial = 0;
} while (written < nbytes && n < iovcount);
return (written);
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbaddata:
t_errno = TBADDATA;
goto error;
tlook:
t_errno = TLOOK;
goto error;
error:
if (!written) {
if (t_errno != TLOOK && __xnet_t_look(fd))
goto tlook;
return (-1);
}
return (written);
}
int
__xnet_t_sndv_r(int fd, const struct t_iovec *iov, unsigned int iovcount, int flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_sndv(fd, iov, iovcount, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_sndv_r,t_sndv@@XNET_1.0");
#if 0
int
__xnet_t_sndvopt(int fd, struct t_optmgmt *options, const struct t_iovec *iov,
unsigned int iovcount, int flags)
{
struct _t_user *user;
int written = 0, nbytes, i;
if (!(user = __xnet_t_tstuser(fd, 0, (1 << T_COTS) | (1 << T_COTS_ORD),
TSF_DATA_XFER | TSF_WREQ_ORDREL)))
goto error;
#ifdef DEBUG
if (!iov)
goto einval;
if (options && (options->opt.len < 0 || (options->opt.len > 0 && !options->opt.buf)))
goto einval;
#endif
if (options && options->opt.len > __xnet_u_max_options(user))
goto tbadopt;
if (iovcount == 0 || iovcount > _T_IOV_MAX)
goto tbaddata;
for (nbytes = 0, i = 0; i < iovcount; nbytes += iov[i].iov_len, i++) ;
if (nbytes == 0 && !(user->info.flags & T_SNDZERO))
goto tbaddata;
if (nbytes > ((flags & T_EXPEDITED) ? __xnet_u_max_etsdu(user) : __xnet_u_max_tsdu(user)))
goto tbaddata;
{
size_t opt_len = (options && options->opt.len > 0) ? options->opt.len : 0;
int band = (flags & T_EXPEDITED) ? 1 : 0;
int n = 0, partial = 0;
struct {
struct T_optdata_req prim;
unsigned char opt[opt_len];
} req;
struct strbuf ctrl, data;
ctrl.maxlen = 0;
ctrl.len = sizeof(req);
ctrl.buf = (char *) &req;
data.maxlen = 0;
data.len = nbytes;
data.buf = NULL;
req.prim.PRIM_type = T_OPTDATA_REQ;
req.prim.DATA_flag =
((flags & T_EXPEDITED) ? T_ODF_EX : 0) | ((flags & T_MORE) ? T_ODF_MORE : 0);
req.prim.OPT_length = opt_len;
req.prim.OPT_offset = opt_len ? sizeof(req.prim) : 0;
if (opt_len)
memcpy(req.opt, options->opt.buf, opt_len);
do {
do {
data.len = min(__xnet_u_max_tidu(user), iov[n].iov_len - partial);
data.buf = iov[n].iov_base + partial;
req.prim.DATA_flag = (((flags & T_EXPEDITED)) ? T_ODF_EX : 0)
| (((flags & T_MORE) || (written + data.len < nbytes)) ?
T_ODF_MORE : 0);
if (__xnet_t_putpmsg(fd, &ctrl, &data, band, MSG_BAND) == -1)
goto error;
partial += data.len;
written += data.len;
} while (partial < iov[n].iov_len);
n++;
partial = 0;
} while (written < nbytes && n < iovcount);
return (written);
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
#endif
tbaddata:
t_errno = TBADDATA;
goto error;
tbadopt:
t_errno = TBADOPT;
goto error;
error:
if (!written)
return (-1);
return (written);
}
int
__xnet_t_sndvopt_r(int fd, struct t_optmgmt *options, const struct t_iovec *iov,
unsigned int iovcount, int flags)
{
int ret = -1;
pthread_cleanup_push_defer_np(__xnet_t_putuser, &fd);
if (__xnet_t_getuser(fd)) {
if ((ret = __xnet_t_sndvopt(fd, options, iov, iovcount, flags)) == -1)
pthread_testcancel();
__xnet_t_putuser(&fd);
} else
pthread_testcancel();
pthread_cleanup_pop_restore_np(0);
return (ret);
}
__asm__(".symver __xnet_t_sndvopt_r,t_sndvopt@@XNET_1.0");
#endif
int
__xnet_t_sndvudata(int fd, struct t_unitdata *unitdata, struct t_iovec *iov, unsigned int iovcount)
{
struct _t_user *user;
int nbytes, i;
if (!(user = __xnet_t_tstuser(fd, T_DATA, (1 << T_CLTS), TSF_IDLE)))
goto error;
if ((__xnet_t_look(fd) & ~T_DATA) > 0)
goto tlook;
#ifdef DEBUG
if (!unitdata || !iov)
goto einval;
#endif
if (iovcount == 0 || iovcount > _T_IOV_MAX)
goto tbaddata;
for (nbytes = 0, i = 0; i < iovcount; nbytes += iov[i].iov_len, i++) ;
if (unitdata && unitdata->addr.len > __xnet_u_max_addr(user))
goto tbadaddr;
if (unitdata && unitdata->opt.len > __xnet_u_max_options(user))
goto tbadopt;
if (nbytes > __xnet_u_max_tsdu(user))
goto tbaddata;
if (nbytes > __xnet_u_max_tidu(user))
goto tbaddata;
if (nbytes == 0 && !(user->info.flags & T_SNDZERO))
goto tbaddata;
{
size_t add_len = (unitdata && unitdata->addr.len > 0) ? unitdata->addr.len : 0;
size_t opt_len = (unitdata && unitdata->opt.len > 0) ? unitdata->opt.len : 0;
int offset, n;
struct {
struct T_unitdata_req prim;
unsigned char addr[add_len];
unsigned char opt[opt_len];
} req;
struct strbuf ctrl, data;
ctrl.maxlen = 0;
ctrl.len = sizeof(req);
ctrl.buf = (char *) &req;
data.maxlen = 0;
data.len = nbytes;
data.buf = NULL;
if (!(data.buf = (char *) malloc(nbytes)))
goto enomem;
for (n = 0, offset = 0; n < iovcount; offset += iov[n].iov_len, n++)
memcpy(data.buf + offset, iov[n].iov_base, iov[n].iov_len);
req.prim.PRIM_type = T_UNITDATA_REQ;
req.prim.DEST_length = add_len;
req.prim.DEST_offset = add_len ? sizeof(req.prim) : 0;
req.prim.OPT_length = opt_len;
req.prim.OPT_offset = opt_len ? sizeof(req.prim) + add_len : 0;
if (add_len)
memcpy(req.addr, unitdata->addr.buf, add_len);
if (opt_len)
memcpy(req.addr + add_len, unitdata->opt.buf, opt_len);
if (__xnet_t_putmsg(fd, &ctrl, &data, 0))
goto error;
return (0);
}
#ifdef DEBUG
einval:
errno = EINVAL;
goto tsyserr;
#endif
enomem:
errno = ENOMEM;
goto tsyserr;
tsyserr:
t_errno = TSYSERR;
goto error;
tbaddata:
t_errno = TBADDATA;
goto error;
tbadopt |