📄 xnet.c
字号:
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; tbadf: t_errno = TBADF; 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);}char *t_alloc(int fd, int type, int fields) __attribute__ ((alias("__xnet_t_alloc_r")));/** * @fn int t_bind(int fd, const struct t_bind *req, struct t_bind *ret) * @brief Bind an address to a transport endpoint. * @param fd A file descriptor indicating the transport endpoint to bind. * @param req A t_bind structure indicating the bind parameters. * @param ret A t_bind structure to return the bind result. * * This function is NOT a thread cancellation point. * t_bind() is NOT a thread cancellation point; however, ioctl(2) might be; * therefore, we disable cancellation for the duration of the call. */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);}int t_bind(int fd, const struct t_bind *req, struct t_bind *ret) __attribute__ ((alias("__xnet_t_bind_r")));/** * @fn int t_close(int fd) * @brief Close a transport endpoint. * @param fd A file descriptor for the transport endpoint to close. * * This function is a thread cancellation point. t_close() is a thread * cancellation point, and so it close(2); therefore, we defer cancellation * until the call completes. */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);}/** * @brief recursive t_close function. * @param fd A file descriptor for the transport endpoint to close. * * This is again a little different that most of the _r wrappers: we take a * write lock on the _t_fds list so that we are able to delete the file * descriptor from the list. This will block most other threads from * performing functions on the list, also, we must wait for a quiet period * until all other functions that read lock the list are not being used. If * you are sure that the close will only be performed by one thread and that * no other thread will act on the file descriptor until close returns, use * the non-recursive version. */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);}int t_close(int fd) __attribute__ ((alias("__xnet_t_close_r")));/** * @fn int t_connect(int fd, const struct t_call *sndcall, struct t_call *rcvcall) * @brief Establish a transport connection. * @param fd the transport endpoint to connect. * @param sndcall a pointer to a t_call structure specifying the peer addres, options and data. * @param rcvcall a pointer to a t_call structure returning the responding address, options and data. * * This function is a thread cancellation point. */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_peek(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_peek(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);}int t_connect(int fd, const struct t_call *sndcall, struct t_call *rcvcall) __attribute__ ((alias("__xnet_t_connect_r")));/** * @fn int t_error(const char *errmsg) * @brief Print an error message. * @param errmsg the error message to print. * * This function is NOT a thread cancellation point. */int__xnet_t_error(const char *errmsg){ fprintf(stderr, "%s: %s\n", errmsg, __xnet_t_strerror(t_errno));}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);}int t_error(const char *errmsg) __attribute__ ((alias("__xnet_t_error_r")));/** * @fn int t_free(void *ptr, int type) * @brief free an XTI library structure. * @param ptr a pointer to the structure to free. * @param type the type of the structure pointed to. * * This function is NOT a thread cancellation point. * * Frees the specified datastructure. Any buffers remaining in the * datastructure (with non-NULL netbuf buf elements) will be freed using * free(2) as well. This can be used to free a structure allocated with * malloc(2) and not necessarily allocated with t_alloc(3). */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);}int t_free(void *ptr, int type) __attribute__ ((alias("__xnet_t_free")));/** * @fn int t_getinfo(int fd, struct t_info *info)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -