⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xnet.c

📁 This a separate release of the OpenSS7 X/Open XTI/TLI library, TLI modules (timod, tirdwr) and the I
💻 C
📖 第 1 页 / 共 5 页
字号:
				 */				if (user->data.len > 0)					memcpy(user->datbuf, user->data.buf, user->data.len);				user->data.buf = user->datbuf;				udata->len = 0;			}		}		break;	default:		goto tlook;	}	return (user->event);      cleanup:	while (ret != -1 && (ret & (MORECTL | MOREDATA)))		ret = __xnet_t_getmsg(fd, &user->ctrl, &user->data, &flag);	goto tsync;      getmsg_error:	t_errno = TSYSERR;	goto error;      tlook:	t_errno = TLOOK;	goto error;      tsync:	__xnet_u_reset_event(user);	/* discard current event */	user->flags |= TUF_SYNC_REQUIRED;	goto tproto;      tproto:	t_errno = TPROTO;	goto error;      error:	return (-1);}/** * @internal * @brief get the next event on the transport endpoint. * @param fd a file descriptor for the transport endpoint. * * Returns the current, or obtains the current, event for the transport * endpoing and completes elements in the user data structure representing the * transport endpoint.  The control and data parts of any retrieved messages * are cached in the user structure and information interpreted and * appropriate flags set. */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);			/*			   There is a little extra handling for data indications 			 */			switch (user->prim) {			case -1:	/* just data */				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;      getmsg_error:	t_errno = TSYSERR;	goto error;      tsync:	__xnet_u_reset_event(user);	/* discard current event */	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 int__xnet_lock_rdlock(pthread_rwlock_t * rwlock){	return pthread_rwlock_rdlock(rwlock);}static int__xnet_lock_wrlock(pthread_rwlock_t * rwlock){	return pthread_rwlock_wrlock(rwlock);}static void__xnet_lock_unlock(void *rwlock){	pthread_rwlock_unlock(rwlock);}static 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);}static int__xnet_user_rdlock(struct _t_user *user){	return __xnet_lock_rdlock(&user->lock);}static int__xnet_user_wrlock(struct _t_user *user){	return __xnet_lock_wrlock(&user->lock);}static 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;}/** * @internal * @brief Get a locked transport user endpoint structure. * @param fd the file descriptor for which to get the associated endpoint. * * This is a range-checked array lookup of the library user structure * associated with the specified file descriptor.  In addition, this function * takes the necessary locks for thread-safe operation. */static struct _t_user *__xnet_t_getuser(int fd){	struct _t_user *user;	int err;	if ((err = __xnet_list_rdlock()))		goto list_lock_error;	if (0 > fd || fd >= OPEN_MAX || !(user = _t_fds[fd]))		goto tbadf;	if ((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);}/** * @internal * @brief Test information about a transport endpoint. * @param fd the file descriptor for which to test the associated endpoint. * @param expect the event anticipated on the transport endpoint. * @param servtype the service type anticipated on the transport endpoint. * @param states the flag mask of the states anticipated for the transport endpoint. * * This is a range-checked array lookup of the library user structure * associated with the specified file descriptor.  In addition, this function * checks for expected events, service types and states as follows: * * When expect is not -1, if there is a current event on the transport * endpoint and that event is not the same as the expected event, then the * call will fail (return NULL) and set t_errno to @c T_LOOK. * * servtype is a bit mask of the service types expected for the transport * endpoint.  If the service type of the transport endpoint is not one of the * service types in the mask, then the call will fail (return NULL) and set * t_errno to @c TNOTSUPPORT.  To accept any service type, set servtype to -1. * * states is a bit mask of the (TPI) states expected for the transport * endpoint.  If the state of the transport endpoing is not one of the states * in the mask, then the call will fail (return NULL) and set t_errno to * @c TOUTSTATE.  To accept any state, set states to -1. */static struct _t_user *__xnet_t_tstuser(int fd, const int expect, const int servtype, const int states){	struct _t_user *user;	if (0 > fd || fd >= OPEN_MAX || !(user = _t_fds[fd]))		goto tbadf;	if (user->flags & TUF_SYNC_REQUIRED)		goto tproto;	if (user->event && user->event != expect && expect != -1)		goto tlook;	if (!((1 << user->info.servtype) & servtype))		goto tnotsupport;	if (!(user->statef & states))		goto toutstate;	return (user);      toutstate:	t_errno = TOUTSTATE;	goto error;      tnotsupport:	t_errno = TNOTSUPPORT;	goto error;      tlook:	t_errno = TLOOK;	goto error;      tproto:	t_errno = TPROTO;	goto error;      tbadf:	t_errno = TBADF;	goto error;      error:	return (NULL);}/** * @internal * @brief A version of ioctl(2) with XTI errors. * @param fd A file descriptor upon which to issue an IO control. * @param cmd The IO control command. * @param arg Argument to the IO control command. * * Our timod @c TI_ ioctls return the error codes (if any) in the return value * rather than errno.  If we get a non-zero return value, it indicates that we * need to unpack the ti and unix error codes and place them in the * appropriate error numbers. */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);	}}/** * @internal * @brief A version of ioctl(2) with XTI errors. * @param fd A file descriptor upon which to issue an IO control. * @param cmd The IO control command. * @param arg Argument to the IO control command. * @param arglen The length of the argument. * * This is a simple matter of packing an otherwise tranparent IO control into * a strioctl buffer and issuing an I_STR IO control instead.  This calls * __xnet_t_ioctl(), so it understands how to properly unpack timod XTI and UNIX * error codes. */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);}/** * @fn t_accept(int fd, int resfd, const struct t_call *call) * @brief accept a connection indication * @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. * * This function is NOT a thread cancellation point.  t_accept() is NOT a a * thread cancellation point; therefore, we disable cancellation for the * duration of the call. */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_peek(fd) > 0)		goto tlook;	if (__xnet_t_peek(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;	/*	   Check if we need to bind the responding stream to the responding address.  This also rules out the case	   where the listening stream and the responding stream are the same address. 	 */	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;		/*		   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:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -