📄 xnet.c
字号:
/* There is no way to pass the responding address to the stream as there is in the NPI, therefore, we must bind the stream to the proper responding address before accepting the connection indication. This sets the local name associated with the accepting stream. */ 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); } /* XNS 5.2 says that if the responding stream is already bound that it must be bound to the same address a specified in call->addr, so we don't check */ { 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) __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_peek(fd) > 0 || __xnet_t_peek(resfd) > 0)) goto tlook; return (-1);}/** @brief The reentrant version of __xnet_t_accept(). * @param fd the file descriptor upon which the connection indication was received. * @param resfd the file descriptor upon which to accept the transport connection. * @param call a pointer to a t_call structure describing the responding transport endpoint. * @version XNET_1.0 * @par Alias: * This symbol is an implementation of t_accept(). * * This function is NOT a thread cancellation point. t_accept(3) is NOT a a * thread cancellation point; therefore, we disable cancellation for the * duration of the call. */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);}/** @fn int t_accept(int fd, int resfd, const struct t_call *call) * @param fd the file descriptor upon which the connection indication was received. * @param resfd the file descriptor upon which to accept the transport connection. * @param call a pointer to a t_call structure describing the responding transport endpoint. * @version XNET_1.0 * @par Alias: * This symbol is a strong alias of __xnet_t_accept_r(). */__asm__(".symver __xnet_t_accept_r,t_accept@@XNET_1.0");/** @brief Add a leaf to a point to multipoint connection. * @param fd A file descriptor for the transport user endpoint. * @param leafid The identifier for the leaf. * @param addr A netbuf(3) structure describing the address of the added leaf. * @version XNET_1.0 * * This XTI Liubrary function is only used for ATM. It is used to add a leaf * to a point to multipoint connection. This function does not translate to * a TPI message exchange, but invokes a t_optmgmt call on an existing ATM * connection. */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; /** The t_addleaf function requires an operating-system specific blocking mechanism to know when to check for the leaf status indication. The most obvious approach is to have the ATM transport service provider send a signal to the stream head when an indication has arrived. What signal (SIGPOLL, SIGIO, SIGUSR) is a question. Nevertheless, we can check our open flags here and either decide to block on a poll or not to check for the indication that the addition was successful. We do not do this yet. We just always return nodata. It is the caller's responsibility to check with t_rcvleafchange(). */ 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 /* defined HAVE_XTI_ATM_H */ t_errno = TNOTSUPPORT; return (-1);#endif /* defined HAVE_XTI_ATM_H */}#pragma weak __xnet_t_addleaf_r/** @brief The reentrant version of __xnet_t_addleaf(). * @param fd A file descriptor for the transport user endpoint. * @param leafid The identifier for the leaf. * @param addr A netbuf(3) structure describing the address of the added leaf. * @version XNET_1.0 * @par Alias: * This function is an implementation of t_addleaf(). * * This function is NOT a thread cancellation point. * t_addleaf() is NOT a thread cancellation point, but ioctl(2) is; therefore, * we disable cancellation for the duration of the call. * * This XTI Liubrary function is only used for ATM. It is used to add a leaf * to a point to multipoint connection. This function does not translate to * a TPI message exchange, but invokes a t_optmgmt call on an existing ATM * connection. */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);}/** @fn int t_addleaf(int fd, int leafid, struct netbuf *addr) * @param fd A file descriptor for the transport user endpoint. * @param leafid The identifier for the leaf. * @param addr A netbuf(3) structure describing the address of the added leaf. * @version XNET_1.0 * @par Alias: * This symbol is a weak alias of __xnet_t_addleaf_r(). */__asm__(".symver __xnet_t_addleaf_r,t_addleaf@@XNET_1.0");/** * @brief Allocate an XTI structure and initialize fields. * @param fd A file descriptor for the transport user endpoint. * @param type The type of structure to allocate. * @param fields The fields in the structure to initialize. * @version XNET_1.0 * @par Alias: * This function is an implementation of t_alloc(). * * This function is NOT a thread cancellation point. * * Allocate the requested library structure and initialize the requested * fields. This consists of allocating the structure itself and allocating * buffers for any of the requested fields. * * It would be more efficient if we allocated the structure and the buffers * together in a single allocation. We would probably get better memory * performance if all of the pieces were kept contiguous. However, the user * has the possibility of separately freeing the buffers and the t_free() * function does exactly that. * * t_alloc() is NOT a thread cancellation point; therefore, we defer * cancellation for the duration of the call. Note that there are no inherent * cancellation points within __xnet_t_alloc(). */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; if (user->info.servtype == T_CLTS) goto tnostructype; 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; if (user->info.servtype == T_CLTS) goto tnostructype; if (!(discon = (struct t_discon *) malloc(sizeof(*discon)))) goto badalloc; memset(discon, 0, sizeof(*discon)); if (fields & T_UDATA) { int len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -