Example #1
0
/*
 * -----------------------------------------------
 * Maintain in parallel with op_zalloc2
 * Arguments:
 *	timeout	- max. time to wait for locks before giving up
 *      laflag - passed to gvcmx* routines as "laflag" argument;
 *		 originally indicated the request was a Lock or
 *		 zAllocate request (hence the name "laflag"), but
 *		 now capable of holding more values signifying
 *		 additional information
 *
 * Return:
 *	1 - if not timeout specified
 *	if timeout specified:
 *		!= 0 - all the locks int the list obtained, or
 *		0 - blocked
 *	The return result is suited to be placed directly into
 *	the $T variable by the caller if timeout is specified.
 * -----------------------------------------------
 */
int	op_lock2(int4 timeout, unsigned char laflag)	/* timeout is in seconds */
{
	bool		blocked, timer_on;
	signed char	gotit;
	unsigned short	locks_bckout, locks_done;
	int4		msec_timeout;	/* timeout in milliseconds */
	mlk_pvtblk	*pvt_ptr1, *pvt_ptr2, **prior;
	unsigned char	action;

	gotit = -1;
	cm_action = laflag;
	timer_on = (NO_M_TIMEOUT != timeout);
	out_of_time = FALSE;
	if (!timer_on)
		msec_timeout = NO_M_TIMEOUT;
	else
	{
		msec_timeout = timeout2msec(timeout);
		if (0 == msec_timeout)
			out_of_time = TRUE;
		else
			start_timer((TID)&timer_on, msec_timeout, wake_alarm, 0, NULL);
	}
	lckclr();
	for (blocked = FALSE;  !blocked;)
	{
		/* if this is a request for a remote node */
		if (remlkreq)
		{
			if (gotit >= 0)
				gotit = gvcmx_resremlk(cm_action);
			else
				gotit = gvcmx_reqremlk(cm_action, timeout);

			if (!gotit)
			{
				/* only REQIMMED returns false */
				blocked = TRUE;
				break;
			}
		}
		for (pvt_ptr1 = mlk_pvt_root, locks_done = 0;  locks_done < lks_this_cmd;  pvt_ptr1 = pvt_ptr1->next, locks_done++)
		{	/* Go thru the list of all locks to be obtained attempting to lock
			 * each one. If any lock could not be obtained, break out of the loop */
			if (!mlk_lock(pvt_ptr1, 0, TRUE))
			{	/* If lock is obtained */
				pvt_ptr1->granted = TRUE;
				switch (laflag)
				{
				case CM_LOCKS:
					pvt_ptr1->level = 1;
					break;
				case INCREMENTAL:
					pvt_ptr1->level += pvt_ptr1->translev;
					break;
				default:
					GTMASSERT;
					break;
				}
			} else
			{
				blocked = TRUE;
				break;
			}
		}
		/* If we did not get blocked, we are all done */
		if (!blocked)
			break;
		/* We got blocked and need to keep retrying after some time interval */
		if (remlkreq)
			gvcmx_susremlk(cm_action);
		switch (cm_action)
		{
		case CM_LOCKS:
			action = LOCKED;
			break;
		case INCREMENTAL:
			action = INCREMENTAL;
			break;
		default:
			GTMASSERT;
			break;
		}
		for (pvt_ptr2 = mlk_pvt_root, locks_bckout = 0;  locks_bckout < locks_done;
			pvt_ptr2 = pvt_ptr2->next, locks_bckout++)
		{
			assert(pvt_ptr2->granted && (pvt_ptr2 != pvt_ptr1));
			mlk_bckout(pvt_ptr2, action);
		}
		if (dollar_tlevel && (CDB_STAGNATE <= t_tries))
		{
			mlk_unpend(pvt_ptr1);		/* Eliminated the dangling request block */
			if (timer_on)
				cancel_timer((TID)&timer_on);
			t_retry(cdb_sc_needlock);	/* release crit to prevent a deadlock */
		}
		for (;;)
		{
			if (out_of_time || outofband)
			{	/* if time expired  ||  control-c encountered */
				if (outofband || !lk_check_own(pvt_ptr1))
				{	/* If CTL-C, check lock owner */
					if (pvt_ptr1->nodptr)		/* Get off pending list to be sent a wake */
						mlk_unpend(pvt_ptr1);
					/* Cancel all remote locks obtained so far */
					if (remlkreq)
					{
						gvcmx_canremlk();
						gvcmz_clrlkreq();
						remlkreq = FALSE;
					}
					if (outofband)
					{
						cancel_timer((TID)&timer_on);
						outofband_action(FALSE);
					}
					break;
				}
			}
			if (!mlk_lock(pvt_ptr1, 0, FALSE))
			{	/* If we got the lock, break out of timer loop */
				blocked = FALSE;
				if (pvt_ptr1 != mlk_pvt_root)
				{
					rel_quant();		/* attempt to get a full timeslice for maximum chance to get all */
					mlk_unlock(pvt_ptr1);
				}
				break;
			}
			if (pvt_ptr1->nodptr)
				lk_check_own(pvt_ptr1);		/* clear an abandoned owner */
			hiber_start_wait_any(LOCK_SELF_WAKE);
		}
		if (blocked  &&  out_of_time)
			break;
	}
	if (remlkreq)
	{
		gvcmz_clrlkreq();
		remlkreq = FALSE;
	}
	if (timer_on)
	{
		cancel_timer((TID)&timer_on);
		if (blocked)
		{
			for (prior = &mlk_pvt_root;  *prior;)
			{
				if (!(*prior)->granted)
				{	/* if entry was never granted, delete list entry */
					mlk_pvtblk_delete(prior);
				} else
					prior = &((*prior)->next);
			}
			mlk_stats.n_user_locks_fail++;
			return (FALSE);
		}
	}
	mlk_stats.n_user_locks_success++;
	return (TRUE);
}
Example #2
0
/*
 * -----------------------------------------------
 * Maintain in parallel with op_zalloc2
 * Arguments:
 *	timeout	- max. time to wait for locks before giving up
 *      laflag - passed to gvcmx* routines as "laflag" argument;
 *		 originally indicated the request was a Lock or
 *		 zAllocate request (hence the name "laflag"), but
 *		 now capable of holding more values signifying
 *		 additional information
 *
 * Return:
 *	1 - if not timeout specified
 *	if timeout specified:
 *		!= 0 - all the locks int the list obtained, or
 *		0 - blocked
 *	The return result is suited to be placed directly into
 *	the $T variable by the caller if timeout is specified.
 * -----------------------------------------------
 */
int	op_lock2(int4 timeout, unsigned char laflag)	/* timeout is in seconds */
{
	boolean_t	blocked, timer_on;
	signed char	gotit;
	unsigned short	locks_bckout, locks_done;
	int4		msec_timeout;	/* timeout in milliseconds */
	mlk_pvtblk	*pvt_ptr1, *pvt_ptr2, **prior;
	unsigned char	action;
	ABS_TIME	cur_time, end_time, remain_time;
	mv_stent	*mv_zintcmd;

	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	gotit = -1;
	cm_action = laflag;
	out_of_time = FALSE;
	if (timeout < 0)
		timeout = 0;
	else if (TREF(tpnotacidtime) < timeout)
		TPNOTACID_CHECK(LOCKTIMESTR);
	if (!(timer_on = (NO_M_TIMEOUT != timeout)))	/* NOTE assignment */
		msec_timeout = NO_M_TIMEOUT;
	else
	{
		msec_timeout = timeout2msec(timeout);
		if (0 == msec_timeout)
		{
			out_of_time = TRUE;
			timer_on = FALSE;
		} else
		{
			mv_zintcmd = find_mvstent_cmd(ZINTCMD_LOCK, restart_pc, restart_ctxt, FALSE);
			if (mv_zintcmd)
			{
				remain_time = mv_zintcmd->mv_st_cont.mvs_zintcmd.end_or_remain;
				if (0 <= remain_time.at_sec)
					msec_timeout = (int4)(remain_time.at_sec * 1000 + remain_time.at_usec / 1000);
				else
					msec_timeout = 0;
				TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last
					= mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_prior;
				TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last
					= mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_ctxt_prior;
				TAREF1(zintcmd_active, ZINTCMD_LOCK).count--;
				assert(0 <= TAREF1(zintcmd_active, ZINTCMD_LOCK).count);
				if (mv_chain == mv_zintcmd)
					POP_MV_STENT(); /* just pop if top of stack */
				else
				{       /* flag as not active */
					mv_zintcmd->mv_st_cont.mvs_zintcmd.command = ZINTCMD_NOOP;
					mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_check = NULL;
				}
			}
			if (0 < msec_timeout)
			{
				sys_get_curr_time(&cur_time);
				add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
				start_timer((TID)&timer_on, msec_timeout, wake_alarm, 0, NULL);
			} else
			{
				out_of_time = TRUE;
				timer_on = FALSE;
			}
		}
	}
	lckclr();
	for (blocked = FALSE;  !blocked;)
	{	/* if this is a request for a remote node */
		if (remlkreq)
		{
			if (gotit >= 0)
				gotit = gvcmx_resremlk(cm_action);
			else
				gotit = gvcmx_reqremlk(cm_action, msec_timeout);	/* REQIMMED if 2nd arg == 0 */
			if (!gotit)
			{	/* only REQIMMED returns false */
				blocked = TRUE;
				break;
			}
		}
		for (pvt_ptr1 = mlk_pvt_root, locks_done = 0;  locks_done < lks_this_cmd;  pvt_ptr1 = pvt_ptr1->next, locks_done++)
		{	/* Go thru the list of all locks to be obtained attempting to lock
			 * each one. If any lock could not be obtained, break out of the loop
			 */
			if (!mlk_lock(pvt_ptr1, 0, TRUE))
			{	/* If lock is obtained */
				pvt_ptr1->granted = TRUE;
				switch (laflag)
				{
				case CM_LOCKS:
					pvt_ptr1->level = 1;
					break;
				case INCREMENTAL:
					if (pvt_ptr1->level < 511) /* The same lock can not be incremented more than 511 times. */
						pvt_ptr1->level += pvt_ptr1->translev;
					else
						level_err(pvt_ptr1);
					break;
				default:
					GTMASSERT;
					break;
				}
			} else
			{
				blocked = TRUE;
				break;
			}
		}
		/* If we did not get blocked, we are all done */
		if (!blocked)
			break;
		/* We got blocked and need to keep retrying after some time interval */
		if (remlkreq)
			gvcmx_susremlk(cm_action);
		switch (cm_action)
		{
		case CM_LOCKS:
			action = LOCKED;
			break;
		case INCREMENTAL:
			action = INCREMENTAL;
			break;
		default:
			GTMASSERT;
			break;
		}
		for (pvt_ptr2 = mlk_pvt_root, locks_bckout = 0;  locks_bckout < locks_done;
			pvt_ptr2 = pvt_ptr2->next, locks_bckout++)
		{
			assert(pvt_ptr2->granted && (pvt_ptr2 != pvt_ptr1));
			mlk_bckout(pvt_ptr2, action);
		}
		if (dollar_tlevel && (CDB_STAGNATE <= t_tries))
		{	/* upper TPNOTACID_CHECK conditioned on no short timeout; this one rel_crits to avoid potential deadlock */
			assert(TREF(tpnotacidtime) >= timeout);
			TPNOTACID_CHECK(LOCKTIMESTR);
		}
		for (;;)
		{
			if (out_of_time || outofband)
			{	/* if time expired || control-c, tptimeout, or jobinterrupt encountered */
				if (outofband || !lk_check_own(pvt_ptr1))
				{	/* If CTL-C, check lock owner */
					if (pvt_ptr1->nodptr)		/* Get off pending list to be sent a wake */
						mlk_unpend(pvt_ptr1);
					/* Cancel all remote locks obtained so far */
					if (remlkreq)
					{
						gvcmx_canremlk();
						gvcmz_clrlkreq();
						remlkreq = FALSE;
					}
					if (outofband)
					{
						if (timer_on && !out_of_time)
						{
							cancel_timer((TID)&timer_on);
							timer_on = FALSE;
						}
						if (!out_of_time && (NO_M_TIMEOUT != timeout))
						{	/* get remain = end_time - cur_time */
							sys_get_curr_time(&cur_time);
							remain_time = sub_abs_time(&end_time, &cur_time);
							if (0 <= remain_time.at_sec)
								msec_timeout = (int4)(remain_time.at_sec * 1000
									+ remain_time.at_usec / 1000);
							else
								msec_timeout = 0;	/* treat as out_of_time */
							if (0 >= msec_timeout)
							{
								out_of_time = TRUE;
								timer_on = FALSE;	/* as if LOCK :0 */
								break;
							}
							PUSH_MV_STENT(MVST_ZINTCMD);
							mv_chain->mv_st_cont.mvs_zintcmd.end_or_remain = remain_time;
							mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_check = restart_ctxt;
							mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_check = restart_pc;
							/* save current information from zintcmd_active */
							mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_prior
								= TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last;
							mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_prior
								= TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last;
							TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last = restart_pc;
							TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last = restart_ctxt;
							TAREF1(zintcmd_active, ZINTCMD_LOCK).count++;
							mv_chain->mv_st_cont.mvs_zintcmd.command = ZINTCMD_LOCK;
							outofband_action(FALSE);	/* no return */
						}
					}
					break;
				}
			}
			if (!mlk_lock(pvt_ptr1, 0, FALSE))
			{	/* If we got the lock, break out of timer loop */
				blocked = FALSE;
				if (pvt_ptr1 != mlk_pvt_root)
				{
					rel_quant();		/* attempt to get a full timeslice for maximum chance to get all */
					mlk_unlock(pvt_ptr1);
				}
				break;
			}
			if (pvt_ptr1->nodptr)
				lk_check_own(pvt_ptr1);		/* clear an abandoned owner */
			hiber_start_wait_any(LOCK_SELF_WAKE);
		}
		if (blocked && out_of_time)
			break;
	}
	if (remlkreq)
	{
		gvcmz_clrlkreq();
		remlkreq = FALSE;
	}
	if (NO_M_TIMEOUT != timeout)
	{	/* was timed or immediate */
		if (timer_on && !out_of_time)
			cancel_timer((TID)&timer_on);
		if (blocked)
		{
			for (prior = &mlk_pvt_root;  *prior;)
			{
				if (!(*prior)->granted)
				{	/* if entry was never granted, delete list entry */
					mlk_pvtblk_delete(prior);
				} else
					prior = &((*prior)->next);
			}
			mlk_stats.n_user_locks_fail++;
			return (FALSE);
		}
	}
	mlk_stats.n_user_locks_success++;
	return (TRUE);
}
Example #3
0
short	iott_readfl (mval *v, int4 length, int4 timeout)	/* timeout in seconds */
{
	boolean_t	ret, nonzerotimeout, timed;
	uint4		mask;
	unsigned char	inchar, *temp;
#ifdef __MVS__
	unsigned char	asc_inchar;
#endif
	int		dx, msk_in, msk_num, outlen, rdlen, save_errno, selstat, status, width;
	int4		msec_timeout;			/* timeout in milliseconds */
	io_desc		*io_ptr;
	d_tt_struct	*tt_ptr;
	io_terminator	outofbands;
	io_termmask	mask_term;
	unsigned char	*zb_ptr, *zb_top;
	ABS_TIME	cur_time, end_time;
	fd_set		input_fd;
	struct timeval	input_timeval;
	struct timeval	save_input_timeval;

	error_def(ERR_CTRAP);
	error_def(ERR_IOEOF);
	error_def(ERR_NOPRINCIO);

	assert(stringpool.free >= stringpool.base);
	assert(stringpool.free <= stringpool.top);
	io_ptr = io_curr_device.in;
	tt_ptr = (d_tt_struct *)(io_ptr->dev_sp);
	assert(dev_open == io_ptr->state);
	iott_flush(io_curr_device.out);
	width = io_ptr->width;
	if (stringpool.free + length > stringpool.top)
		stp_gcol (length);
	outlen = 0;
	/* ---------------------------------------------------------
	 * zb_ptr is be used to fill-in the value of $zb as we go
	 * If we drop-out with error or otherwise permaturely,
	 * consider $zb to be null.
	 * ---------------------------------------------------------
	 */
	zb_ptr = io_ptr->dollar.zb;
	zb_top = zb_ptr + sizeof(io_ptr->dollar.zb) - 1;
	*zb_ptr = 0;
	io_ptr->esc_state = START;
	io_ptr->dollar.za = 0;
	io_ptr->dollar.zeof = FALSE;
	v->str.len = 0;
	dx = (int)io_ptr->dollar.x;
	ret = TRUE;
	temp = stringpool.free;
	mask = tt_ptr->term_ctrl;
	mask_term = tt_ptr->mask_term;
	if (mask & TRM_NOTYPEAHD)
		TCFLUSH(tt_ptr->fildes, TCIFLUSH, status);
	if (mask & TRM_READSYNC)
	{
		DOWRITERC(tt_ptr->fildes, &dc1, 1, status);
		if (0 != status)
		{
			io_ptr->dollar.za = 9;
			rts_error(VARLSTCNT(1) status);
		}
	}
	nonzerotimeout = FALSE;
	if (NO_M_TIMEOUT == timeout)
	{
		timed = FALSE;
		input_timeval.tv_sec = 100;
		msec_timeout = NO_M_TIMEOUT;
	} else
	{
		timed = TRUE;
		input_timeval.tv_sec = timeout;
		msec_timeout = timeout2msec(timeout);
		if (!msec_timeout)
			iott_mterm(io_ptr);
		else
		{
			nonzerotimeout = TRUE;
   			sys_get_curr_time(&cur_time);
			add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
		}
	}
	input_timeval.tv_usec = 0;
	do
	{
		if (outofband)
		{
			outlen = 0;
			if (!msec_timeout)
				iott_rterm(io_ptr);
			outofband_action(FALSE);
			break;
		}
		errno = 0;
		FD_ZERO(&input_fd);
		FD_SET(tt_ptr->fildes, &input_fd);
		assert(0 != FD_ISSET(tt_ptr->fildes, &input_fd));
		/* the checks for EINTR below are valid and should not be converted to EINTR
		 * wrapper macros, since the select/read is not retried on EINTR.
		 */
		save_input_timeval = input_timeval;	/* take a copy and pass it because select() below might change it */
		selstat = select(tt_ptr->fildes + 1, (void *)&input_fd, (void *)NULL, (void *)NULL, &save_input_timeval);
		if (selstat < 0)
		{
			if (EINTR != errno)
				goto term_error;
		} else if (0 == selstat)
		{
			if (timed)
			{
				ret = FALSE;
				break;
			}
			continue;	/* select() timeout; keep going */
		} else if (0 < (rdlen = read(tt_ptr->fildes, &inchar, 1)))	/* This read is protected */
		{
			assert(0 != FD_ISSET(tt_ptr->fildes, &input_fd));
			/* --------------------------------------------------
			 * set prin_in_dev_failure to FALSE to indicate that
			 * input device is working now.
			 * --------------------------------------------------
			 */
			prin_in_dev_failure = FALSE;
			if (tt_ptr->canonical)
			{
				if (0 == inchar)
				{
					/* --------------------------------------
					 * This means that the device has hungup
					 * --------------------------------------
					 */
					io_ptr->dollar.zeof = TRUE;
					io_ptr->dollar.x = 0;
					io_ptr->dollar.za = 9;
					io_ptr->dollar.y++;
					if (io_ptr->error_handler.len > 0)
						rts_error(VARLSTCNT(1) ERR_IOEOF);
					break;
				} else
					io_ptr->dollar.zeof = FALSE;
			}
			if (mask & TRM_CONVERT)
				NATIVE_CVT2UPPER(inchar, inchar);
                        GETASCII(asc_inchar,inchar);
			if ((dx >= width) && io_ptr->wrap && !(mask & TRM_NOECHO))
			{
				DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL));
				dx = 0;
			}
			if ((' ' > INPUT_CHAR) && (tt_ptr->enbld_outofbands.mask & (1 << INPUT_CHAR)))
			{
				outlen = 0;
				io_ptr->dollar.za = 9;
				std_dev_outbndset(INPUT_CHAR);	/* it needs ASCII?	*/
				outofband = 0;
				if (!msec_timeout)
					iott_rterm(io_ptr);
				rts_error(VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is);
				break;
			}
			if ((0 != (mask & TRM_ESCAPE))
			     && ((NATIVE_ESC == inchar) || (START != io_ptr->esc_state)))
			{
				if (zb_ptr >= zb_top)
				{	/* $zb overflow */
					io_ptr->dollar.za = 2;
					break;
				}
				*zb_ptr++ = inchar;
				iott_escape(zb_ptr - 1, zb_ptr, io_ptr);
				*(zb_ptr - 1) = INPUT_CHAR;     /* need to store ASCII value    */
				if (FINI == io_ptr->esc_state)
					break;
				if (BADESC == io_ptr->esc_state)
				{	/* Escape sequence failed parse */
					io_ptr->dollar.za = 2;
					break;
				}
				/* --------------------------------------------------------------------
				 * In escape sequence...do not process further, but get next character
				 * --------------------------------------------------------------------
				 */
			} else
			{	/* SIMPLIFY THIS! */
				msk_num = (uint4)INPUT_CHAR / NUM_BITS_IN_INT4;
				msk_in = (1 << ((uint4)INPUT_CHAR % NUM_BITS_IN_INT4));
				if (msk_in & mask_term.mask[msk_num])
				{
					*zb_ptr++ = INPUT_CHAR;
					break;
				}
				if (((int)inchar == tt_ptr->ttio_struct->c_cc[VERASE]) && !(mask & TRM_PASTHRU))
				{
					if ((0< outlen) && (0 < dx))
					{
						outlen--;
						dx--;
						*temp--;
						if (!(mask & TRM_NOECHO))
						{
							DOWRITERC(tt_ptr->fildes, eraser, sizeof(eraser), status);
							if (0 != status)
								goto term_error;
						}
					}
				} else
				{
					if (!(mask & TRM_NOECHO))
					{
						DOWRITERC(tt_ptr->fildes, &inchar, 1, status);
						if (0 != status)
							goto term_error;
					}
					*temp++ = inchar;
					outlen++;
					dx++;
				}
			}
		} else if (0 == rdlen)
		{
			if (0 < selstat)
			{	/* this should be the only possibility */
				io_ptr->dollar.zeof = TRUE;
				io_ptr->dollar.x = 0;
				io_ptr->dollar.za = 0;
				io_ptr->dollar.y++;
				if (io_curr_device.in == io_std_device.in)
				{
					if (!prin_in_dev_failure)
						prin_in_dev_failure = TRUE;
					else
					{
                                        	send_msg(VARLSTCNT(1) ERR_NOPRINCIO);
                                        	stop_image_no_core();
					}
                                }
				if (io_ptr->dollar.zeof)
				{
					io_ptr->dollar.za = 9;
					rts_error(VARLSTCNT(1) ERR_IOEOF);
				} else
				{
					io_ptr->dollar.zeof = TRUE;
					io_ptr->dollar.za = 0;
					if (0 < io_ptr->error_handler.len)
						rts_error(VARLSTCNT(1) ERR_IOEOF);
				}
				break;
			}
			if (0 == errno)
			{	/* eof */
				io_ptr->dollar.zeof = TRUE;
				io_ptr->dollar.x = 0;
				io_ptr->dollar.za = 0;
				io_ptr->dollar.y++;
				if (0 < io_ptr->error_handler.len)
					rts_error(VARLSTCNT(1) ERR_IOEOF);
				break;
			}
		} else if (EINTR != errno)	/* rdlen < 0 */
			goto term_error;
		if (nonzerotimeout)
		{
			sys_get_curr_time(&cur_time);
			cur_time = sub_abs_time(&end_time, &cur_time);
			if (0 > cur_time.at_sec)
			{
				ret = FALSE;
				break;
			}
			input_timeval.tv_sec = cur_time.at_sec;
			input_timeval.tv_usec = cur_time.at_usec;
		}
	} while (outlen < length);
	*zb_ptr++ = 0;
	if (!msec_timeout)
	{
		iott_rterm(io_ptr);
		if (0 == outlen)
			ret = FALSE;
	}
	if (mask & TRM_READSYNC)
	{
		DOWRITERC(tt_ptr->fildes, &dc3, 1, status);
		if (0 != status)
		{
			io_ptr->dollar.za = 9;
			rts_error(VARLSTCNT(1) status);
		}
	}
	if (outofband)
	{
		v->str.len = 0;
		io_ptr->dollar.za = 9;
		return(FALSE);
	}
	v->str.len = outlen;
	v->str.addr = (char *)stringpool.free;
	if (!(mask & TRM_NOECHO))
	{
		if ((io_ptr->dollar.x += v->str.len) >= io_ptr->width && io_ptr->wrap)
		{
			io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width);
			if (io_ptr->length)
				io_ptr->dollar.y %= io_ptr->length;
			io_ptr->dollar.x %= io_ptr->width;
			if (0 == io_ptr->dollar.x)
				DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL));
		}
	}
	return ((short)ret);

term_error:
	save_errno = errno;
	io_ptr->dollar.za = 9;
	if (!msec_timeout)
		iott_rterm(io_ptr);
	rts_error(VARLSTCNT(1) save_errno);
	return FALSE;
}
Example #4
0
/*
 * ---------------------------------------------------
 * Job command main entry point
 * ---------------------------------------------------
 */
int	op_job(int4 argcnt, ...)
{
	va_list		var;
	int4		i;
	mval		*label, *inp;
	int4		offset;
	mval		*routine, *param_buf;
	int4		timeout;	/* timeout in seconds */
	int4		msec_timeout;	/* timeout in milliseconds */
	boolean_t	timed, single_attempt, non_exit_return;
	unsigned char	buff[128], *c;
	int4		status, exit_stat, term_sig, stop_sig;
	pid_t		zjob_pid = 0; 	/* zjob_pid should exactly match in type with child_pid(ojstartchild.c) */
	int		pipe_fds[2], pipe_status;
#	ifdef _BSD
	union wait	wait_stat;
#	else
	int4		wait_stat;
#	endif
	job_params_type job_params;
	char		combuf[128];
	mstr		command;
	job_parm	*jp;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	VAR_START(var, argcnt);
	assert(argcnt >= 5);
	label = va_arg(var, mval *);
	offset = va_arg(var, int4);
	routine = va_arg(var, mval *);
	param_buf = va_arg(var, mval *);
	timeout = va_arg(var, int4);	/* in seconds */
	argcnt -= 5;
	/* initialize $zjob = 0, in case JOB fails */
	dollar_zjob = 0;
	MV_FORCE_DEFINED(label);
	MV_FORCE_DEFINED(routine);
	MV_FORCE_DEFINED(param_buf);
	/* create a pipe to channel the PID of the jobbed off process(J) from middle level
	 * process(M) to the current process (P)
	 */
	OPEN_PIPE(pipe_fds, pipe_status);
	if (-1 == pipe_status)
	{
		va_end(var);
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Error creating pipe"), errno);
	}
	jobcnt++;
	command.addr = &combuf[0];
	/* Setup job parameters by parsing param_buf and using label, offset, routine, & timeout).  */
	job_params.routine = routine->str;
	job_params.label = label->str;
	job_params.offset = offset;
	ojparams(param_buf->str.addr, &job_params);
	/*
	 * Verify that entryref to JOB command is not NULL.
	 */
	if (!job_params.routine.len)
	{
		va_end(var);
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JOBFAIL, 0, ERR_NULLENTRYREF, 0);
	}
	/* Clear the buffers */
	flush_pio();
	/* Start the timer */
	ojtimeout = FALSE;
	if (timeout < 0)
		timeout = 0;
	else if (TREF(tpnotacidtime) < timeout)
		TPNOTACID_CHECK(JOBTIMESTR);
	if (NO_M_TIMEOUT == timeout)
	{
		timed = FALSE;
		msec_timeout = NO_M_TIMEOUT;
	} else
	{
		timed = TRUE;
		msec_timeout = timeout2msec(timeout);
		if (msec_timeout > 0)
			start_timer((TID)&tid, msec_timeout, job_timer_handler, 0, NULL);
	}
	if (argcnt)
	{
		jp = job_params.parms = (job_parm *)malloc(SIZEOF(job_parm) * argcnt);
		i = argcnt;
		for(;;)
		{
			inp = va_arg(var, mval *);
			jp->parm = inp;
			if (0 == --i)
				break;
			jp->next = jp + 1;
			jp = jp->next;
		}
		jp->next = 0;
	} else
void	iosocket_tls(mval *optionmval, int4 timeoutarg, mval *tlsid, mval *password, mval *extraarg)
{	/* note extraarg is not currently used */
	int4			length, flags, timeout, msec_timeout, status, status2, len, errlen, devlen, tls_errno, save_errno;
	io_desc			*iod;
	d_socket_struct 	*dsocketptr;
	socket_struct		*socketptr;
	char			optionstr[MAX_TLSOPTION], idstr[MAX_TLSID_LEN], passwordstr[GTM_PASSPHRASE_MAX_ASCII + 1];
	const char		*errp;
	tls_option		option;
	gtm_tls_socket_t	*tlssocket;
	ABS_TIME		cur_time, end_time;
#	ifdef USE_POLL
	struct pollfd		fds;
#	else
	fd_set			fds, *readfds, *writefds;
	struct timeval		timeout_spec, *timeout_ptr;
#	endif

	iod = io_curr_device.out;
	assert(gtmsocket == iod->type);
	dsocketptr = (d_socket_struct *)iod->dev_sp;
	if (0 >= dsocketptr->n_socket)
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSOCKETINDEV);
		return;
	}
	if (dsocketptr->n_socket <= dsocketptr->current_socket)
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
		return;
	}
	if (dsocketptr->mupintr)
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
	socketptr = dsocketptr->socket[dsocketptr->current_socket];
	ENSURE_DATA_SOCKET(socketptr);
	if (socket_tcpip != socketptr->protocol)
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, RTS_ERROR_MVAL(optionmval),
			LEN_AND_LIT("but socket is not TCP"));
		return;
	}
	if (socket_connected != socketptr->state)
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("/TLS"),
			LEN_AND_LIT("but socket not connected"));
		return;
	}
	if (NULL != tlsid)
	{
		length = tlsid->str.len;
		if (MAX_TLSID_LEN < (length + 1))	/* for null */
		{
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("TLSID"), LEN_AND_LIT("too long"));
			return;
		}
		STRNCPY_STR(idstr, tlsid->str.addr, length);
		idstr[length] = '\0';
	} else
		idstr[0] = '\0';
	if (NULL != password)
	{
		length = password->str.len;
		if (GTM_PASSPHRASE_MAX_ASCII < length)
		{
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_LIT("passphrase"),
				LEN_AND_LIT("too long"));
			return;
		}
		STRNCPY_STR(passwordstr, password->str.addr, length);
		passwordstr[length] = '\0';
	} else
		passwordstr[0] = '\0';
	length = MIN(MAX_TLSOPTION, optionmval->str.len);
	lower_to_upper((uchar_ptr_t)optionstr, (uchar_ptr_t)optionmval->str.addr, length);
	if (0 == memcmp(optionstr, "CLIENT", length))
		option = tlsopt_client;
	else if (0 == memcmp(optionstr, "SERVER", length))
		option = tlsopt_server;
	else if (0 == memcmp(optionstr, "RENEGOTIATE", length))
		option = tlsopt_renegotiate;
	else
		option = tlsopt_invalid;
	memcpy(iod->dollar.device, "0", SIZEOF("0"));
	if (NO_M_TIMEOUT != timeoutarg)
	{
		msec_timeout = timeout2msec(timeoutarg);
		sys_get_curr_time(&cur_time);
		add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
	} else
		msec_timeout = -1;
	if ((tlsopt_client == option) || (tlsopt_server == option))
	{	/* most of the setup is common */
		if (socketptr->tlsenabled)
		{
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSPARAM, 4, LEN_AND_STR(optionstr),
				LEN_AND_LIT("but TLS already enabled"));
			return;
		}
		assertpro((0 >= socketptr->buffered_length) && (0 >= socketptr->obuffer_length));
		if (NULL == tls_ctx)
		{	/* first use of TLS */
			if (-1 == gtm_tls_loadlibrary())
			{
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSDLLNOOPEN, 0, ERR_TEXT, 2, LEN_AND_STR(dl_err));
				return;
			}
			if (NULL == (tls_ctx = (gtm_tls_init(GTM_TLS_API_VERSION, GTMTLS_OP_INTERACTIVE_MODE))))
			{
				errp = gtm_tls_get_error();
				len = SIZEOF(ONE_COMMA) - 1;
				memcpy(iod->dollar.device, ONE_COMMA, len);
				errlen = STRLEN(errp);
				devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
				memcpy(&iod->dollar.device[len], errp, devlen + 1);
				if (devlen < errlen)
					iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
				if (socketptr->ioerror)
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSINIT, 0, ERR_TEXT, 2, errlen, errp);
				if (NO_M_TIMEOUT != timeoutarg)
					dollar_truth = FALSE;
				return;
			}
		}
		socketptr->tlsenabled = TRUE;
		flags = GTMTLS_OP_SOCKET_DEV | ((tlsopt_client == option) ? GTMTLS_OP_CLIENT_MODE : 0);
		socketptr->tlssocket = gtm_tls_socket(tls_ctx, NULL, socketptr->sd, idstr, flags);
		if (NULL == socketptr->tlssocket)
		{
			socketptr->tlsenabled = FALSE;
			errp = gtm_tls_get_error();
			len = SIZEOF(ONE_COMMA) - 1;
			memcpy(iod->dollar.device, ONE_COMMA, len);
			errlen = STRLEN(errp);
			devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
			memcpy(&iod->dollar.device[len], errp, devlen + 1);
			if (devlen < errlen)
				iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
			if (socketptr->ioerror)
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSCONVSOCK, 0, ERR_TEXT, 2, errlen, errp);
			if (NO_M_TIMEOUT != timeoutarg)
				dollar_truth = FALSE;
			return;
		}
		status = 0;
#		ifndef	USE_POLL
		if (NO_M_TIMEOUT == timeoutarg)
			timeout_ptr = NULL;
		else
		{
			timeout_spec.tv_sec = msec_timeout / 1000;
			timeout_spec.tv_usec = (msec_timeout % 1000) * 1000;	/* remainder in millsecs to microsecs */
			timeout_ptr = &timeout_spec;
		}
#		endif
		do
		{
			status2 = 0;
			if (0 != status)
			{
#				ifdef USE_POLL
				fds.fd = socketptr->sd;
				fds.events = (GTMTLS_WANT_READ == status) ? POLLIN : POLLOUT;
#				else
				readfds = writefds = NULL;
				assertpro(FD_SETSIZE > socketptr->sd);
				FD_ZERO(&fds);
				FD_SET(socketptr->sd, &fds);
				writefds = (GTMTLS_WANT_WRITE == status) ? &fds : NULL;
				readfds = (GTMTLS_WANT_READ == status) ? &fds : NULL;
#				endif
				POLL_ONLY(if (-1 == (status2 = poll(&fds, 1, msec_timeout))))
				SELECT_ONLY(if (-1 == (status2 = select(socketptr->sd + 1, readfds, writefds, NULL, timeout_ptr))))
				{
					save_errno = errno;
					if (EAGAIN == save_errno)
					{
						rel_quant();	/* allow resources to become available */
						status2 = 0;	/* treat as timeout */
					} else if (EINTR == save_errno)
						status2 = 0;
				}
			} else
				status2 = 1;	/* do accept/connect first time */
			if (0 < status2)
			{
				if (tlsopt_server == option)
					status = gtm_tls_accept((gtm_tls_socket_t *)socketptr->tlssocket);
				else
					status = gtm_tls_connect((gtm_tls_socket_t *)socketptr->tlssocket);
			}
			if ((0 > status2) || ((status != 0) && ((GTMTLS_WANT_READ != status) && (GTMTLS_WANT_WRITE != status))))
			{
				if (0 != status)
				{
					tls_errno = gtm_tls_errno();
					if (0 > tls_errno)
						errp = gtm_tls_get_error();
					else
						errp = STRERROR(tls_errno);
				} else
					errp = STRERROR(save_errno);
				socketptr->tlsenabled = FALSE;
				len = SIZEOF(ONE_COMMA) - 1;
				memcpy(iod->dollar.device, ONE_COMMA, len);
				errlen = STRLEN(errp);
				devlen = MIN((SIZEOF(iod->dollar.device) - len - 1), errlen);
				memcpy(&iod->dollar.device[len], errp, devlen + 1);
				if (devlen < errlen)
					iod->dollar.device[SIZEOF(iod->dollar.device) - 1] = '\0';
				if (socketptr->ioerror)
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TLSHANDSHAKE, 0,
						ERR_TEXT, 2, errlen, errp);
				return;
			}
			if ((0 != status) && (0 <= status2))	/* not accepted/connected and not error */
			{	/* check for timeout if not error or want read or write */
				if ((0 != timeoutarg) && (NO_M_TIMEOUT != timeoutarg))
				{
					sys_get_curr_time(&cur_time);
					cur_time = sub_abs_time(&end_time, &cur_time);
					if (0 >= cur_time.at_sec)
					{	/* no more time */
						gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
						socketptr->tlsenabled = FALSE;
						dollar_truth = FALSE;
						return;
					} else
					{	/* adjust msec_timeout for poll/select */
#					ifdef	USE_POLL
						msec_timeout = (cur_time.at_sec * 1000) + (cur_time.at_usec / 1000);
#					else
						timeout_spec.tv_sec = cur_time.at_sec;
						timeout_spec.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
#					endif
					}
				} else if (0 == timeoutarg)
				{	/* only one chance */
					gtm_tls_session_close((gtm_tls_socket_t **)&socketptr->tlssocket);
					socketptr->tlsenabled = FALSE;
					dollar_truth = FALSE;
					return;
				}
				continue;
			}
		} while ((GTMTLS_WANT_READ == status) || (GTMTLS_WANT_WRITE == status));
		/* turn on output buffering */
		if (0 == socketptr->obuffer_size)
			socketptr->obuffer_size = socketptr->buffer_size;
		socketptr->obuffer_length = socketptr->obuffer_offset = 0;
		socketptr->obuffer_wait_time = DEFAULT_WRITE_WAIT;
		socketptr->obuffer_flush_time = DEFAULT_WRITE_WAIT * 2;	/* until add device parameter */
		socketptr->obuffer = malloc(socketptr->obuffer_size);
	} else if (tlsopt_renegotiate == option)
Example #6
0
short	iorm_read (mval *v, int4 timeout) /* timeout in seconds */
{
	boolean_t	ret, timed;
	int4		msec_timeout;	/* timeout in milliseconds */
	uint4		width;
	char		inchar, *temp;
	int		flags;
	int		fcntl_res;
	int4		i;
	io_desc		*io_ptr;
	d_rm_struct	*rm_ptr;
	int4		status;
	TID		timer_id;

	error_def(ERR_IOEOF);

	assert(stringpool.free >= stringpool.base);
	assert(stringpool.free <= stringpool.top);

	io_ptr = io_curr_device.in;
	assert (io_ptr->state == dev_open);
	rm_ptr = (d_rm_struct*) (io_ptr->dev_sp);
	if (io_ptr->dollar.x  &&  rm_ptr->lastop == RM_WRITE)
	{
		if (!io_ptr->dollar.za)
			iorm_wteol(1, io_ptr);
		io_ptr->dollar.x = 0;
	}

	rm_ptr->lastop = RM_READ;
	timer_id = (TID) iorm_read;
	width = io_ptr->width;
	if (stringpool.free + width > stringpool.top)
		stp_gcol (width);
	i = 0;
	ret = TRUE;
	temp = (char*) stringpool.free;
	out_of_time = FALSE;
	if (timeout == NO_M_TIMEOUT)
	{
		timed = FALSE;
		msec_timeout = NO_M_TIMEOUT;
	}
	else
	{
		timed = TRUE;
		msec_timeout = timeout2msec(timeout);
		if (msec_timeout > 0)
		{
			start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL);
		}
		else
		{
			out_of_time = TRUE;
			FCNTL2(rm_ptr->fildes, F_GETFL, flags);
                        FCNTL3(rm_ptr->fildes, F_SETFL, (flags | O_NDELAY), fcntl_res);
		}
	}
	errno = 0;
	if (rm_ptr->fixed)
	{
		/*
		 * the check for EINTR below is valid and should not be converted to an EINTR
		 * wrapper macro, since it might be a timeout.
		 */
		DOREADRLTO(rm_ptr->fildes, temp, width, out_of_time, status);
		if (0 > status)
		{
			i = 0;
			if (errno == EINTR  &&  out_of_time)
				status = -2;
		}
		else
			i = status;
	}
	else
	{
		do
		{
			if ((status = getc (rm_ptr->filstr)) != EOF)
			{
				inchar = (unsigned char) status;
				if (inchar == NATIVE_NL)
					break;
				*temp++ = inchar;
				i++;
			}
			else
			{
				inchar = 0;
				if (errno == 0)
					status = 0;
				else if (errno == EINTR)
				{
					if (out_of_time)
						status = -2;
				        else
						continue;	/* Ignore interruption if wasn't our timeout */
				}
				break;
			}
		} while (i < width);
	}
	if (status == EOF  &&  errno != EINTR)
	{
		io_ptr->dollar.za = 9;
		v->str.len = 0;
		if ((timed) && (!out_of_time))
			cancel_timer(timer_id);
		rts_error(VARLSTCNT(1) errno);
	}

	if (timed)
	{
		if (msec_timeout == 0)
		{
			FCNTL3(rm_ptr->fildes, F_SETFL, flags, fcntl_res);
			if (rm_ptr->fifo && status == 0)
				ret = FALSE;
		}
		else
		{
			if (out_of_time)
				ret = FALSE;
			else
				cancel_timer(timer_id);
		}
	}

	if (status == 0  &&  i == 0  &&  !rm_ptr->fifo)
	{
		v->str.len = 0;
		if (io_ptr->dollar.zeof == TRUE)
		{
			io_ptr->dollar.za = 9;
			rts_error(VARLSTCNT(1) ERR_IOEOF);
		}
		io_ptr->dollar.zeof = TRUE;
		io_ptr->dollar.x = 0;
		io_ptr->dollar.za = 0;
		io_ptr->dollar.y++;
		if (io_ptr->error_handler.len > 0)
		{	rts_error(VARLSTCNT(1) ERR_IOEOF);
		}
	}
	else
	{
		v->str.len = i;
		v->str.addr = (char *) stringpool.free;
		if (!rm_ptr->fixed && inchar == NATIVE_NL)
		{
		    	io_ptr->dollar.x = 0;
			io_ptr->dollar.y++;
		}
		else
			if ((io_ptr->dollar.x += i) >= io_ptr->width && io_ptr->wrap)
			{
				io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width);
				if(io_ptr->length)
					io_ptr->dollar.y %= io_ptr->length;
				io_ptr->dollar.x %= io_ptr->width;
			}
	}
	io_ptr->dollar.za = 0;
	return((short) ret);
}
Example #7
0
int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /* host needs to be NULL terminated */
{
	boolean_t		no_time_left = FALSE, error_given = FALSE;
	char			temp_addr[SA_MAXLEN + 1], addr[SA_MAXLEN + 1];
	char 			*from, *to, *errptr, *temp_ch;
	char			ipname[SA_MAXLEN];
	int			match, sock, sendbufsize, ii, on = 1, temp_1 = -2;
	GTM_SOCKLEN_TYPE	size;
	int4                    rv, msec_timeout;
	struct addrinfo		*ai_ptr = NULL, *remote_ai_ptr = NULL, *remote_ai_head, hints;
	char			port_buffer[NI_MAXSERV], *brack_pos;

	int			host_len, addr_len, port_len;
	char                    msg_buffer[1024];
	mstr                    msg_string;
	ABS_TIME                cur_time, end_time;
	fd_set                  tcp_fd;
	struct sockaddr_storage peer;
	short 			retry_num;
	int 			save_errno, errlen;
	const char		*terrptr;
	int			errcode;
	boolean_t		af;

	msg_string.len = SIZEOF(msg_buffer);
	msg_string.addr = msg_buffer;
	/* ============================= initialize structures ============================== */
	if (NULL != host)
	{
		host_len = strlen(host);
		if ('[' == host[0])
		{
			brack_pos = memchr(host, ']', SA_MAXLEN);
			if (NULL == brack_pos || (&host[1] == brack_pos))
			{
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC);
				return -1;
			}
			addr_len = brack_pos - &(host[1]);
			memcpy(addr, &host[1], addr_len);
			if ('\0' != *(brack_pos + 1))
			{	/* not allowed to have special symbols other than [ and ] */
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC);
				return -1;
			}
		} else
		{	/* IPv4 address only */
			addr_len = strlen(host);
			if (0 == addr_len)
			{
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC);
				return -1;
			}
			memcpy(addr, &host[0], addr_len);
		}
		addr[addr_len] = '\0';
		CLIENT_HINTS(hints);
		port_len = 0;
		I2A(port_buffer, port_len, port);
		port_buffer[port_len]='\0';
		if (0  != (errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_head)))
		{
			RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
			return -1;
		}
	}

	/* ============================== do the connection ============================== */
	if (passive)
	{
		struct timeval  utimeout, save_utimeout;
		int 		lsock;

		af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET);
		lsock = socket(af, SOCK_STREAM, IPPROTO_TCP);
		if (-1 == lsock)
		{
			af = AF_INET;
			if (-1 == (lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
			{
				save_errno = errno;
				errptr = (char *)STRERROR(save_errno);
        	 		errlen = STRLEN(errptr);
				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr);
				assert(FALSE);
				return -1;
			}
		}
		SERVER_HINTS(hints, af);
		/* We can only listen on our own system */
		port_len = 0;
		I2A(port_buffer, port_len, port);
		port_buffer[port_len]='\0';
		if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr)))
		{
			RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
			return -1;

		}
		/* allow multiple connections to the same IP address */
		if (-1 == setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on)))
		{
			save_errno = errno;
			(void)close(lsock);
			errptr = (char *)STRERROR(save_errno);
         		errlen = STRLEN(errptr);
                	gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
					LEN_AND_LIT("SO_REUSEADDR"), save_errno, errlen, errptr);
			assert(FALSE);
			return -1;
		}
		if (-1 == bind(lsock, ai_ptr->ai_addr, ai_ptr->ai_addrlen))
		{
			save_errno = errno;
			(void)close(lsock);
			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
				   LEN_AND_LIT("bind()"), CALLFROM, save_errno);
			return -1;
		}
		freeaddrinfo(ai_ptr);
		/* establish a queue of length MAX_CONN_PENDING for incoming connections */
		if (-1 == listen(lsock, MAX_CONN_PENDING))
		{
			save_errno = errno;
			(void)close(lsock);
			errptr = (char *)STRERROR(save_errno);
			errlen = STRLEN(errptr);
			gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr);
			assert(FALSE);
			return -1;
		}
		if (NO_M_TIMEOUT != timeout)
		{
			msec_timeout = timeout2msec(timeout);
			sys_get_curr_time(&cur_time);
			add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
			utimeout.tv_sec = timeout;
			utimeout.tv_usec = 0;
		}
		assertpro(FD_SETSIZE > lsock);
		FD_ZERO(&tcp_fd);
		while (TRUE)
		{
			while (TRUE)
			{
				/* The check for EINTR below is valid and should not be converted to an EINTR wrapper macro
				 * since it might be a timeout.
				 */
				FD_SET(lsock, &tcp_fd);
                                save_utimeout = utimeout;
				rv = select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0,
					(NO_M_TIMEOUT == timeout) ? (struct timeval *)0 : &utimeout);
				save_errno = errno;
                                utimeout = save_utimeout;
				if ((0 <= rv) || (EINTR != save_errno))
					break;
				if (NO_M_TIMEOUT != timeout)
				{
					sys_get_curr_time(&cur_time);
					cur_time = sub_abs_time(&end_time, &cur_time);
					if (0 >= (utimeout.tv_sec = cur_time.at_sec))
					{
						rv = 0;
						break;
					}
				}
			}
			if (0 == rv)
			{
				(void)close(lsock);
				util_out_print("Listening timed out.\n", TRUE);
				assert(FALSE);
				return -1;
			} else  if (0 > rv)
			{
				(void)close(lsock);
				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
					   LEN_AND_LIT("select()"), CALLFROM, save_errno);
				assert(FALSE);
				return -1;
			}
			size = SIZEOF(struct sockaddr_storage);
			ACCEPT_SOCKET(lsock, (struct sockaddr*)(&peer), &size, sock);
			if (FD_INVALID == sock)
			{
				save_errno = errno;
#				ifdef __hpux
				if (ENOBUFS == save_errno)
					continue;
#				endif
				(void)close(lsock);
				errptr = (char *)STRERROR(save_errno);
				errlen = STRLEN(errptr);
				gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
				assert(FALSE);
				return -1;
			}
			GETNAMEINFO((struct sockaddr*)(&peer), size, temp_addr, SA_MAXLEN + 1, NULL, 0, NI_NUMERICHOST, errcode);
			if (0 != errcode)
			{
				RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
				return -1;
			}
#			ifdef	DEBUG_ONLINE
			PRINTF("Connection is from : %s\n", &temp_addr[0]);
#			endif
			break;
			/* previously there is following check here
			 * if ((0 == temp_sin_addr) || (0 == memcmp(&addr[0], &temp_addr[0], strlen(addr))))
                         * However, temp_sin_addr is always 0 on server side, and addr(local address) shoud not equal to
			 * temp_addr(remote address), so the entire check should be removed
			 */
		}
		(void)close(lsock);
	} else
	{	/* client side (connection side) */
		if (NO_M_TIMEOUT != timeout)
Example #8
0
short	iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 timeout)
{
	boolean_t		no_time_left = FALSE, timed;
	char			addr[SA_MAXLEN+1], *errptr, sockaddr[SA_MAXLEN+1],
				temp_addr[SA_MAXLEN+1], temp_ch;
	unsigned char		ch, len;
	int4			length, width;
	unsigned short		port;
	int4			errlen, msec_timeout;
	int			ii, status, size,
				on = 1,
				p_offset = 0,
				temp_1 = -2;
	TID			timer_id;
	ABS_TIME		cur_time, end_time, time_for_read, save_time_for_read;
	d_tcp_struct		*tcpptr, newtcp;
	io_desc			*ioptr;
	struct sockaddr_in	peer;		/* socket address + port */
	fd_set			tcp_fd;
	int			lsock;

	error_def(ERR_DEVPARMNEG);
	error_def(ERR_INVADDRSPEC);
	error_def(ERR_INVPORTSPEC);
	error_def(ERR_IPADDRREQ);
	error_def(ERR_OPENCONN);
	error_def(ERR_SOCKACPT);
	error_def(ERR_SOCKINIT);
	error_def(ERR_SOCKPARMREQ);
	error_def(ERR_SOCKWAIT);
	error_def(ERR_TEXT);

#ifdef	DEBUG_TCP
	PRINTF("iotcp_open.c >>>   tt = %d\n", t);
#endif
	ioptr = dev->iod;
	assert((params) *(pp->str.addr + p_offset) < (unsigned char)n_iops);
	assert(0 != ioptr);
	assert(ioptr->state >= 0 && ioptr->state < n_io_dev_states);
	assert(tcp == ioptr->type);
	if (dev_never_opened == ioptr->state)
	{
		ioptr->dev_sp = (void *)malloc(sizeof(d_tcp_struct));
		memset(ioptr->dev_sp, 0, sizeof(d_tcp_struct));
	}
	tcpptr = (d_tcp_struct *)ioptr->dev_sp;
	if (dev_never_opened == ioptr->state)
	{
		ioptr->state	= dev_closed;
		ioptr->width	= TCPDEF_WIDTH;
		ioptr->length	= TCPDEF_LENGTH;
		ioptr->wrap	= TRUE;
		if (-1 == iotcp_fillroutine())
			assert(FALSE);
	}
	ioptr->dollar.zeof = FALSE;
	newtcp = *tcpptr;
	memcpy(newtcp.dollar_device, LITZERO, sizeof(LITZERO));
	newtcp.passive = FALSE;
	while (iop_eol != *(pp->str.addr + p_offset))
	{
		switch	(ch = *(pp->str.addr + p_offset++))
		{
		case	iop_width:
			GET_LONG(width, pp->str.addr + p_offset);
			if (0 == width)
				newtcp.width = TCPDEF_WIDTH;
			else if (width > 0)
				newtcp.width = width;
			else
				rts_error(VARLSTCNT(1)	ERR_DEVPARMNEG);
			break;
		case	iop_length:
			GET_LONG(length, pp->str.addr + p_offset);
			if (0 == length)
				newtcp.length = TCPDEF_LENGTH;
			else if (length > 0)
				newtcp.length = length;
			else
				rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
			break;
		case	iop_listen:
			newtcp.passive = TRUE;
			break;
		case	iop_socket:
			len = *(pp->str.addr + p_offset);
			memset(sockaddr, 0, SA_MAXLEN+1);
			memcpy(sockaddr, pp->str.addr + p_offset + 1, (len <= SA_MAXLEN) ? len : SA_MAXLEN);
			*temp_addr = '\0';
			*addr = '\0';
			port = 0;
			if (SSCANF(sockaddr, "%[^,], %hu", temp_addr, &port) < 2)
			{
				newtcp.sin.sin_addr.s_addr = INADDR_ANY;
				if (SSCANF(sockaddr, ",%hu", &port) < 1)
				{
					rts_error(VARLSTCNT(1) ERR_INVPORTSPEC);
					return	FALSE;
				}
			} else
			{
				ii = 0;
				temp_ch = temp_addr[0];
				while(ISDIGIT(temp_ch) || ('.' == temp_ch))
				{
					ii++;
					temp_ch = temp_addr[ii];
				}
				if ('\0' != temp_ch)
					SPRINTF(addr, "%s", iotcp_name2ip(temp_addr));
				else
					SPRINTF(addr, "%s", temp_addr);
				if ((in_addr_t)-1 == (newtcp.sin.sin_addr.s_addr = tcp_routines.aa_inet_addr(addr)))
				{
					rts_error(VARLSTCNT(1) ERR_INVADDRSPEC);
					return	FALSE;
				}
			}
			newtcp.sin.sin_port = GTM_HTONS(port);
			newtcp.sin.sin_family = AF_INET;
			break;
		case	iop_exception:
			ioptr->error_handler.len = *(pp->str.addr + p_offset);
			ioptr->error_handler.addr = (char *)(pp->str.addr + p_offset + 1);
			s2pool(&ioptr->error_handler);
			break;
		default:
			break;
		}
		p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
			(unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
	}
	if ((0 == newtcp.sin.sin_port) && (0 == newtcp.sin.sin_addr.s_addr))
	{
		rts_error(VARLSTCNT(1) ERR_SOCKPARMREQ);
		return	FALSE;
	}
	/* active connection must have a complete address specification */
	if ((INADDR_ANY == newtcp.sin.sin_addr.s_addr) && !newtcp.passive)
	{
		rts_error(VARLSTCNT(1) ERR_IPADDRREQ);
		return FALSE;
	}
	if (dev_closed == ioptr->state)
	{
		if (newtcp.passive)		/* passive connection */
		{
			/* no listening socket for this addr?  make one. */
			memcpy(ioptr->dev_sp, &newtcp, sizeof(d_tcp_struct));
			if (!(lsock = iotcp_getlsock(dev)))
				return	FALSE;	/* could not create listening socket */
			timer_id = (TID)iotcp_open;
			out_of_time = FALSE;
			time_for_read.at_sec = ((NO_M_TIMEOUT == timeout) ? 0 : 1);
			time_for_read.at_usec = 0;
			if (NO_M_TIMEOUT == timeout)
			{
				timed = FALSE;
				msec_timeout = NO_M_TIMEOUT;
			} else
			{
				timed = TRUE;
				msec_timeout = timeout2msec(timeout);
				if (msec_timeout > 0)
				{       /* there is time to wait */
					sys_get_curr_time(&cur_time);
					add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
					start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL);
				} else
					out_of_time = TRUE;
			}
			for (status = 0; 0 == status; )
			{
				FD_ZERO(&tcp_fd);
				FD_SET(lsock, &tcp_fd);
				/*
				 * Note: the check for EINTR from the select below should remain, as aa_select is a
				 * function, and not all callers of aa_select behave the same when EINTR is returned.
				 */
                                save_time_for_read = time_for_read;
				status = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0, &time_for_read);
                                time_for_read = save_time_for_read;
				if (0 > status)
				{
					if (EINTR == errno && FALSE == out_of_time)
						/* interrupted by a signal which is not OUR timer */
						status = 0;
					else
						break;
				}
				if (outofband)
                        		break;
				if (timed)
				{
					if (msec_timeout > 0)
					{
						sys_get_curr_time(&cur_time);
						cur_time = sub_abs_time(&end_time, &cur_time);
						if (cur_time.at_sec <= 0)
						{
							out_of_time = TRUE;
							cancel_timer(timer_id);
							break;
						}
					} else
						break;
				}
#ifdef __linux__
				time_for_read.at_sec = ((NO_M_TIMEOUT == timeout) ? 0 : 1);
				time_for_read.at_usec = 0;
#endif
			}
			if (timed)
			{
				if (0 != msec_timeout)
				{
					cancel_timer(timer_id);
					if (out_of_time || outofband)
						return FALSE;
					/*if (outofband)
						outofband_action(FALSE);*/
				}
			}
			if (0 > status)
			{
				errptr = (char *)STRERROR(errno);
				errlen = strlen(errptr);
				iotcp_rmlsock((io_desc *)dev->iod);
				rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr);
				return FALSE;
			}
			size = sizeof(struct sockaddr_in);
			status = tcp_routines.aa_accept(lsock, &peer, &size);
			if (-1 == status)
			{
				errptr = (char *)STRERROR(errno);
				errlen = strlen(errptr);
				iotcp_rmlsock((io_desc *)dev->iod);
				rts_error(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
				return FALSE;
			}
			SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(peer.sin_addr),
				GTM_NTOHS(newtcp.sin.sin_port));
			newtcp.socket = status;
		} else			/*	active connection */
		{
			if (NO_M_TIMEOUT != timeout)
			{
				msec_timeout = timeout2msec(timeout);
				sys_get_curr_time(&cur_time);
				add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
			}
			no_time_left = FALSE;
			temp_1 = 1;
			do
			{
				if(1 != temp_1)
					tcp_routines.aa_close(newtcp.socket);
				newtcp.socket = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0);
				if (-1 == newtcp.socket)
				{
					errptr = (char *)STRERROR(errno);
					errlen = strlen(errptr);
					rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
					return FALSE;
				}
				/*	allow multiple connections to the same IP address */
				if	(-1 == tcp_routines.aa_setsockopt(newtcp.socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
				{
					(void)tcp_routines.aa_close(newtcp.socket);
					errptr = (char *)STRERROR(errno);
					errlen = strlen(errptr);
					rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
					return FALSE;
				}
				size=sizeof(newtcp.bufsiz);
				if (-1 == tcp_routines.aa_getsockopt(newtcp.socket, SOL_SOCKET, SO_RCVBUF, &newtcp.bufsiz, &size))
				{
					(void)tcp_routines.aa_close(newtcp.socket);
					errptr = (char *)STRERROR(errno);
					errlen = strlen(errptr);
					rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
					return FALSE;
				}
				/*
				 * Note: the check for EINTR from the connect need not be converted to an EINTR wrapper macro,
				 * since the connect is not retried on EINTR.
				 */
				temp_1 = tcp_routines.aa_connect(newtcp.socket, (struct sockaddr *)&newtcp.sin, sizeof(newtcp.sin));
				if ((temp_1 < 0) && (ECONNREFUSED != errno) && (EINTR != errno))
				{
					(void)tcp_routines.aa_close(newtcp.socket);
					errptr = (char *)STRERROR(errno);
					errlen = strlen(errptr);
					rts_error(VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr);
					return FALSE;
				}
				if ((temp_1 < 0) && (EINTR == errno))
				{
					(void)tcp_routines.aa_close(newtcp.socket);
					return FALSE;
				}
				if ((temp_1 < 0) && (NO_M_TIMEOUT != timeout))
				{
					sys_get_curr_time(&cur_time);
					cur_time = sub_abs_time(&end_time, &cur_time);
					if (cur_time.at_sec <= 0)
						no_time_left = TRUE;
				}
				SHORT_SLEEP(100);		/* Sleep for 100 ms */
			}
			while ((TRUE != no_time_left) && (temp_1 < 0));
			if (temp_1 < 0) /* out of time */
			{
				tcp_routines.aa_close(newtcp.socket);
				return FALSE;
			}
#ifdef	ntohs	/* if it's a macro, use it instead of tcp_routines.aa_ntohs */
			SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(newtcp.sin.sin_addr),
				ntohs(newtcp.sin.sin_port));
#else
			SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(newtcp.sin.sin_addr),
				tcp_routines.aa_ntohs(newtcp.sin.sin_port));
#endif
		}
		memcpy(ioptr->dev_sp, &newtcp, sizeof(d_tcp_struct));
		ioptr->state = dev_open;
	}
#ifdef	DEBUG_TCP
	PRINTF("%s (%d) <<<\n", __FILE__, tcpptr->socket);
#endif
	return TRUE;
}
Example #9
0
#			ifdef	DEBUG_ONLINE
			PRINTF("Connection is from : %s\n", &temp_addr[0]);
#			endif
			break;
			/* previously there is following check here
			 * if ((0 == temp_sin_addr) || (0 == memcmp(&addr[0], &temp_addr[0], strlen(addr))))
                         * However, temp_sin_addr is always 0 on server side, and addr(local address) shoud not equal to
			 * temp_addr(remote address), so the entire check should be removed
			 */
		}
		(void)close(lsock);
	} else
	{	/* client side (connection side) */
		if (NO_M_TIMEOUT != timeout)
		{
			msec_timeout = timeout2msec(timeout);
			sys_get_curr_time(&cur_time);
			add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
		}
		no_time_left = FALSE;
		temp_1 = 1;
		do
		{
			if (1 != temp_1)
				close(sock);
			assert(NULL != remote_ai_head);
			for (remote_ai_ptr = remote_ai_head; NULL != remote_ai_ptr; remote_ai_ptr = remote_ai_ptr->ai_next)
			{
				sock = socket(remote_ai_ptr->ai_family, remote_ai_ptr->ai_socktype,
							      remote_ai_ptr->ai_protocol);
				if (FD_INVALID != sock)
Example #10
0
boolean_t iosocket_wait(io_desc *iod, int4 timepar)
{
	struct 	timeval  	utimeout;
	ABS_TIME		cur_time, end_time;
	struct 	sockaddr_in     peer;           /* socket address + port */
        fd_set    		tcp_fd;
        d_socket_struct 	*dsocketptr;
        socket_struct   	*socketptr, *newsocketptr;
        char            	*errptr;
        int4            	errlen, ii, msec_timeout;
	int			rv, size, max_fd;
	short			len;
        error_def(ERR_SOCKACPT);
        error_def(ERR_SOCKWAIT);
        error_def(ERR_TEXT);
	/* check for validity */
        assert(iod->type == gtmsocket);
        dsocketptr = (d_socket_struct *)iod->dev_sp;
	/* check for events */
	max_fd = 0;
	FD_ZERO(&tcp_fd);
	for (ii = 0; ii < dsocketptr->n_socket; ii++)
	{
		socketptr = dsocketptr->socket[ii];
		if ((socket_listening == socketptr->state) || (socket_connected == socketptr->state))
		{
			FD_SET(socketptr->sd, &tcp_fd);
			max_fd = MAX(max_fd, socketptr->sd);
		}
	}
	utimeout.tv_sec = timepar;
	utimeout.tv_usec = 0;
	msec_timeout = timeout2msec(timepar);
	sys_get_curr_time(&cur_time);
	add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
	for ( ; ; )
	{
		rv = tcp_routines.aa_select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0,
			(timepar == NO_M_TIMEOUT ? (struct timeval *)0 : &utimeout));
		if (0 > rv && EINTR == errno)
		{
			if (OUTOFBANDNOW(outofband))
			{
				rv = 0;		/* treat as time out */
				break;
			}
			sys_get_curr_time(&cur_time);
			cur_time = sub_abs_time(&end_time, &cur_time);
			if (0 > cur_time.at_sec)
			{
				rv = 0;		/* time out */
				break;
			}
			utimeout.tv_sec = cur_time.at_sec;
			utimeout.tv_usec = cur_time.at_usec;
		}
		else
			break;	/* either other error or done */
	}
	if (rv == 0)
	{
		dsocketptr->dollar_key[0] = '\0';
		return FALSE;
	}
	else  if (rv < 0)
	{
		errptr = (char *)STRERROR(errno);
		errlen = strlen(errptr);
		rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr);
		return FALSE;
	}
	/* find out which socket is ready */
	for (ii = 0; ii < dsocketptr->n_socket; ii++)
	{
		socketptr = dsocketptr->socket[ii];
		if (0 != FD_ISSET(socketptr->sd, &tcp_fd))
			break;
	}
	assert(ii < dsocketptr->n_socket);
	if (socket_listening == socketptr->state)
	{
		size = sizeof(struct sockaddr_in);
		rv = tcp_routines.aa_accept(socketptr->sd, &peer, &size);
		if (rv == -1)
		{
			errptr = (char *)STRERROR(errno);
			errlen = strlen(errptr);
			rts_error(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
			return FALSE;
		}
		/* got the connection, create a new socket in the device socket list */
		newsocketptr = (socket_struct *)malloc(sizeof(socket_struct));
		*newsocketptr = *socketptr;
		newsocketptr->sd = rv;
		memcpy(&newsocketptr->remote.sin, &peer, sizeof(struct sockaddr_in));
		SPRINTF(newsocketptr->remote.saddr_ip, "%s", tcp_routines.aa_inet_ntoa(peer.sin_addr));
		newsocketptr->remote.port = GTM_NTOHS(peer.sin_port);
		newsocketptr->state = socket_connected;
		newsocketptr->passive = FALSE;
		for (ii = 0; ii < newsocketptr->n_delimiter; ii++)
		{
			newsocketptr->delimiter[ii].addr = (char *)malloc(socketptr->delimiter[ii].len);
			memcpy(newsocketptr->delimiter[ii].addr, socketptr->delimiter[ii].addr, socketptr->delimiter[ii].len);
		}
		newsocketptr->buffer = (char *)malloc(socketptr->buffer_size);
		newsocketptr->buffer_size = socketptr->buffer_size;
		newsocketptr->buffered_length = socketptr->buffered_offset = 0;
		/* put the new-born socket to the list and create a handle for it */
		iosocket_handle(newsocketptr->handle, &newsocketptr->handle_len, TRUE, dsocketptr);
		dsocketptr->socket[dsocketptr->n_socket++] = newsocketptr;
		dsocketptr->current_socket = dsocketptr->n_socket - 1;
		len = sizeof(CONNECTED) - 1;
		memcpy(&dsocketptr->dollar_key[0], CONNECTED, len);
		dsocketptr->dollar_key[len++] = '|';
		memcpy(&dsocketptr->dollar_key[len], newsocketptr->handle, newsocketptr->handle_len);
		len += newsocketptr->handle_len;
		dsocketptr->dollar_key[len++] = '|';
		memcpy(&dsocketptr->dollar_key[len], newsocketptr->remote.saddr_ip, strlen(newsocketptr->remote.saddr_ip));
		len += strlen(newsocketptr->remote.saddr_ip);
		dsocketptr->dollar_key[len] = '\0';
	}
	else
	{
		assert(socket_connected == socketptr->state);
		dsocketptr->current_socket = ii;
		len = sizeof(READ) - 1;
		memcpy(&dsocketptr->dollar_key[0], READ, len);
		dsocketptr->dollar_key[len++] = '|';
		memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len);
                len += socketptr->handle_len;
                dsocketptr->dollar_key[len++] = '|';
                memcpy(&dsocketptr->dollar_key[len], socketptr->remote.saddr_ip, strlen(socketptr->remote.saddr_ip));
                len += strlen(socketptr->remote.saddr_ip);
                dsocketptr->dollar_key[len] = '\0';
	}
	return TRUE;
}
Example #11
0
int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /* host needs to be NULL terminated */
{
	boolean_t		no_time_left = FALSE, error_given = FALSE;
	char			temp_addr[SA_MAXLEN + 1], addr[SA_MAXLEN + 1];
	char 			*from, *to, *errptr, *temp_ch;
	int			match, sock, sendbufsize, size, ii, on = 1, temp_1 = -2;
	int4                    errlen, rv, msec_timeout;
	struct	sockaddr_in	sin;
	in_addr_t		temp_sin_addr;
	char                    msg_buffer[1024];
	mstr                    msg_string;
	ABS_TIME                cur_time, end_time;
	fd_set                  tcp_fd;
	struct sockaddr_in      peer;

	error_def(ERR_INVADDRSPEC);

	temp_sin_addr = 0;
	msg_string.len = sizeof(msg_buffer);
	msg_string.addr = msg_buffer;
	memset((char *)&sin, 0, sizeof(struct sockaddr_in));

	/* ============================= initialize structures ============================== */
	if (NULL != host)
	{
		temp_ch = host;
		while(ISDIGIT(*temp_ch) || ('.' == *temp_ch))
			temp_ch++;
		if ('\0' != *temp_ch)
			SPRINTF(addr, "%s", iotcp_name2ip(host));
		else
			SPRINTF(addr, "%s", host);

		if (-1 == (temp_sin_addr = tcp_routines.aa_inet_addr(addr)))
		{
			gtm_getmsg(ERR_INVADDRSPEC, &msg_string);
			util_out_print(msg_string.addr, TRUE, ERR_INVADDRSPEC);
			return  -1;
		}
	}

	if (passive)
		/* We can only listen on our own system */
		sin.sin_addr.s_addr = INADDR_ANY;
	else
	{
		if (0 == temp_sin_addr)
		{ 	/* If no address was specified */
			util_out_print("An address has to be specified for an active connection.", TRUE);
			return -1;
		}
		/* Set where to send the connection attempt */
		sin.sin_addr.s_addr = temp_sin_addr;
	}
	sin.sin_port = GTM_HTONS(port);
	sin.sin_family = AF_INET;


	/* ============================== do the connection ============================== */

	if (passive)
	{
		struct timeval  utimeout, save_utimeout;
		int 		lsock;

		lsock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0);
		if (-1 == lsock)
		{
			errptr = (char *)STRERROR(errno);
			errlen = strlen(errptr);
			util_out_print(errptr, TRUE, errno);
			return -1;
		}
		/* allow multiple connections to the same IP address */
		if (-1 == tcp_routines.aa_setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
		{
			errptr = (char *)STRERROR(errno);
			errlen = strlen(errptr);
			(void)tcp_routines.aa_close(lsock);
			util_out_print(errptr, TRUE, errno);
			return -1;
		}
		if (-1 == tcp_routines.aa_bind(lsock, (struct sockaddr *)&sin, sizeof(struct sockaddr)))
		{
			errptr = (char *)STRERROR(errno);
			errlen = strlen(errptr);
			(void)tcp_routines.aa_close(lsock);
			util_out_print(errptr, TRUE, errno);
			return -1;
		}
		/* establish a queue of length MAX_CONN_PENDING for incoming connections */
		if (-1 == tcp_routines.aa_listen(lsock, MAX_CONN_PENDING))
		{
			errptr = (char *)STRERROR(errno);
			errlen = strlen(errptr);
			(void)tcp_routines.aa_close(lsock);
			util_out_print(errptr, TRUE, errno);
			return -1;
		}

		if (NO_M_TIMEOUT != timeout)
		{
			msec_timeout = timeout2msec(timeout);
			sys_get_curr_time(&cur_time);
			add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
			utimeout.tv_sec = timeout;
			utimeout.tv_usec = 0;
		}
		while(1)
		{
			while(1)
			{
				/*
				 * the check for EINTR below is valid and should not be converted to an EINTR
				 * wrapper macro, since it might be a timeout.
				 */
				FD_ZERO(&tcp_fd);
				FD_SET(lsock, &tcp_fd);
                                save_utimeout = utimeout;
				rv = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0,
					(NO_M_TIMEOUT == timeout) ? (struct timeval *)0 : &utimeout);
                                utimeout = save_utimeout;
				if ((0 <= rv) || (EINTR != errno))
					break;
				if (NO_M_TIMEOUT != timeout)
				{
					sys_get_curr_time(&cur_time);
					cur_time = sub_abs_time(&end_time, &cur_time);
					if (0 >= (utimeout.tv_sec = cur_time.at_sec))
					{
						rv = 0;
						break;
					}
				}
			}
			if (0 == rv)
			{
				util_out_print("Listening timed out.\n", TRUE);
				(void)tcp_routines.aa_close(lsock);
				return -1;
			} else  if (0 > rv)
			{
				errptr = (char *)STRERROR(errno);
				errlen = strlen(errptr);
				util_out_print(errptr, TRUE, errno);
				(void)tcp_routines.aa_close(lsock);
				return -1;
			}
			size = sizeof(struct sockaddr_in);
			sock = tcp_routines.aa_accept(lsock, &peer, &size);
			if (-1 == sock)
			{
				errptr = (char *)STRERROR(errno);
				errlen = strlen(errptr);
				util_out_print(errptr, TRUE, errno);
				(void)tcp_routines.aa_close(lsock);
				return -1;
			}
			SPRINTF(&temp_addr[0], "%s", tcp_routines.aa_inet_ntoa(peer.sin_addr));
#ifdef	DEBUG_ONLINE
			PRINTF("Connection is from : %s\n", &temp_addr[0]);
#endif
			/* Check if connection is from whom we want it to be from. Note that this is not a robust check
			   (potential for multiple IP addrs for a resolved name but workarounds for this exist so not a lot
			   of effort has been expended here at this time. Especially since the check is easily spoofed with
			   raw sockets anyway. It is more for the accidental "oops" type check than serious security..
			*/
			if ((0 == temp_sin_addr) || (0 == memcmp(&addr[0], &temp_addr[0], strlen(addr))))
				break;
			else
			{	/* Connection not from expected host */
				(void)tcp_routines.aa_close(sock);
				if (NO_M_TIMEOUT != timeout)
				{
					sys_get_curr_time(&cur_time);
					cur_time = sub_abs_time(&end_time, &cur_time);
					utimeout.tv_sec = ((cur_time.at_sec > 0) ? cur_time.at_sec : 0);
				}
				if (!error_given)
				{
					util_out_print("Connection from !AD rejected and ignored", TRUE,
						       LEN_AND_STR(&temp_addr[0]));
					error_given = TRUE;
				}
			}
		}
		(void)tcp_routines.aa_close(lsock);
	} else
	{
		if (NO_M_TIMEOUT != timeout)
		{
			msec_timeout = timeout2msec(timeout);
			sys_get_curr_time(&cur_time);
			add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
		}
		no_time_left = FALSE;
		temp_1 = 1;
		do
		{
			if (1 != temp_1)
				tcp_routines.aa_close(sock);
			sock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0);
			if (-1 == sock)
			{
				errptr = (char *)STRERROR(errno);
				errlen = strlen(errptr);
				util_out_print(errptr, TRUE, errno);
				return -1;
			}
			/*      allow multiple connections to the same IP address */
			if      (-1 == tcp_routines.aa_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
			{
				(void)tcp_routines.aa_close(sock);
				errptr = (char *)STRERROR(errno);
				errlen = strlen(errptr);
			        util_out_print(errptr, TRUE, errno);
				return -1;
			}
			temp_1 = tcp_routines.aa_connect(sock, (struct sockaddr *)(&sin), sizeof(sin));
			/*
			 * the check for EINTR below is valid and should not be converted to an EINTR
			 * wrapper macro, because other error conditions are checked, and a retry is not
			 * immediately performed.
			 */
			if ((0 > temp_1) && (ECONNREFUSED != errno) && (EINTR != errno))
			{
				(void)tcp_routines.aa_close(sock);
				errptr = (char *)STRERROR(errno);
				errlen = strlen(errptr);
			        util_out_print(errptr, TRUE, errno);
				return -1;
			}
			if ((0 > temp_1) && (EINTR == errno))
			{
				(void)tcp_routines.aa_close(sock);
				util_out_print("Interrupted.", TRUE);
				return -1;
			}
			if ((temp_1 < 0) && (NO_M_TIMEOUT != timeout))
			{
				sys_get_curr_time(&cur_time);
				cur_time = sub_abs_time(&end_time, &cur_time);
				if (cur_time.at_sec <= 0)
					no_time_left = TRUE;
			}
			SHORT_SLEEP(NAP_LENGTH);               /* Sleep for NAP_LENGTH ms */
		} while ((FALSE == no_time_left) && (0 > temp_1));

		if (0 > temp_1) /* out of time */
		{
			tcp_routines.aa_close(sock);
			util_out_print("Connection timed out.", TRUE);
			return -1;
		}
	}

	return sock;
}
Example #12
0
boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz)
{
	int		temp_1 = 1;
	char		*errptr;
	int4            errlen, msec_timeout, real_errno;
	boolean_t	no_time_left = FALSE;
	short		len;
	d_socket_struct *dsocketptr;
	ABS_TIME        cur_time, end_time;

	error_def(ERR_SOCKINIT);
	error_def(ERR_OPENCONN);
	error_def(ERR_TEXT);
	error_def(ERR_GETSOCKOPTERR);
	error_def(ERR_SETSOCKOPTERR);
	dsocketptr = socketptr->dev;
        assert(NULL != dsocketptr);
        dsocketptr->dollar_key[0] = '\0';
	if (timepar != NO_M_TIMEOUT)
	{
		msec_timeout = timeout2msec(timepar);
		sys_get_curr_time(&cur_time);
		add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
	}
	do
	{
		if (1 != temp_1)
		{
			tcp_routines.aa_close(socketptr->sd);
		}
	        if (-1 == (socketptr->sd = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0)))
        	{
                	errptr = (char *)STRERROR(errno);
                	errlen = strlen(errptr);
                	rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
                	return FALSE;
        	}
		temp_1 = 1;
		if (-1 == tcp_routines.aa_setsockopt(socketptr->sd,
				SOL_SOCKET, SO_REUSEADDR, &temp_1, sizeof(temp_1)))
        	{
                	errptr = (char *)STRERROR(errno);
                	errlen = strlen(errptr);
                	rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
					RTS_ERROR_LITERAL("SO_REUSEADDR"), errno, errlen, errptr);
                	return FALSE;
        	}
#ifdef TCP_NODELAY
		temp_1 = socketptr->nodelay ? 1 : 0;
		if (-1 == tcp_routines.aa_setsockopt(socketptr->sd,
				IPPROTO_TCP, TCP_NODELAY, &temp_1, sizeof(temp_1)))
        	{
                	errptr = (char *)STRERROR(errno);
                	errlen = strlen(errptr);
                	rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
					RTS_ERROR_LITERAL("TCP_NODELAY"), errno, errlen, errptr);
                	return FALSE;
        	}
#endif
		if (update_bufsiz)
		{
			if (-1 == tcp_routines.aa_setsockopt(socketptr->sd,
				SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, sizeof(socketptr->bufsiz)))
			{
				errptr = (char *)STRERROR(errno);
         			errlen = strlen(errptr);
                		rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
					RTS_ERROR_LITERAL("SO_RCVBUF"), errno, errlen, errptr);
				return FALSE;
			}
		}
		else
		{
			temp_1 = sizeof(socketptr->bufsiz);
			if (-1 == tcp_routines.aa_getsockopt(socketptr->sd,
				SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, &temp_1))
			{
				errptr = (char *)STRERROR(errno);
         			errlen = strlen(errptr);
                		rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5,
					RTS_ERROR_LITERAL("SO_RCVBUF"), errno, errlen, errptr);
				return FALSE;
			}
		}
		temp_1 = tcp_routines.aa_connect(socketptr->sd,
				(struct sockaddr *)&socketptr->remote.sin, sizeof(socketptr->remote.sin));
		if (temp_1 < 0)
		{
			real_errno = errno;
			no_time_left = TRUE;
			switch (real_errno)
			{
			case ETIMEDOUT	:	/* the other side bound but not listening */
			case ECONNREFUSED :
				if (NO_M_TIMEOUT != timepar)
				{
					sys_get_curr_time(&cur_time);
					cur_time = sub_abs_time(&end_time, &cur_time);
					if (cur_time.at_sec > 0)
						no_time_left = FALSE;
				}
				break;
			case EINTR :
				break;
			default:
				errptr = (char *)STRERROR(real_errno);
				errlen = strlen(errptr);
				rts_error(VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr);
				break;
			}
			if (no_time_left)
			{
				return FALSE;
			}
			hiber_start(100);
		}
	} while (temp_1 < 0);
	/* handle the local information later.
	SPRINTF(socketptr->local.saddr_ip, "%s", tcp_routines.aa_inet_ntoa(socketptr->remote.sin.sin_addr));
	socketptr->local.port = GTM_NTOHS(socketptr->remote.sin.sin_port);
	*/
	socketptr->state = socket_connected;
	/* update dollar_key */
        len = sizeof(ESTABLISHED) - 1;
        memcpy(&dsocketptr->dollar_key[0], ESTABLISHED, len);
        dsocketptr->dollar_key[len++] = '|';
        memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len);
        len += socketptr->handle_len;
        dsocketptr->dollar_key[len++] = '|';
	memcpy(&dsocketptr->dollar_key[len], socketptr->remote.saddr_ip, strlen(socketptr->remote.saddr_ip));
	len += strlen(socketptr->remote.saddr_ip);
	dsocketptr->dollar_key[len] = '\0';
	return TRUE;
}
Example #13
0
int	iotcp_readfl(mval *v, int4 width, int4 timeout)
/* 0 == width is a flag that the caller is read and the length is not actually fixed */
/* timeout in seconds */
{
	/* VMS uses the UCX interface; should support others that emulate it */
	boolean_t	ret, timed, vari;
	int		flags, len, real_errno, save_errno;
	int		i;
	io_desc		*io_ptr;
	d_tcp_struct	*tcpptr;
	int4		status;
	int4		msec_timeout;	/* timeout in milliseconds */
	TID		timer_id;
	ABS_TIME	cur_time, end_time, time_for_read, lcl_time_for_read, zero;
	fd_set		tcp_fd;
	char		*errptr;
	int4		errlen;

	error_def(ERR_IOEOF);
	error_def(ERR_TEXT);
	error_def(ERR_GETSOCKOPTERR);
	error_def(ERR_SETSOCKOPTERR);

#ifdef DEBUG_TCP
	PRINTF("%s >>>\n", __FILE__);
#endif
	assert(stringpool.free >= stringpool.base);
	assert(stringpool.free <= stringpool.top);
	if (0 == width)
	{	/* op_readfl won't do this; must be a call from iotcp_read */
		vari = TRUE;
		width = MAX_READLEN;
	} else
	{
		vari = FALSE;
		width = (width < MAX_READLEN) ? width : MAX_READLEN;
	}
	if (stringpool.free + width > stringpool.top)
		stp_gcol(width);
	io_ptr = io_curr_device.in;
	assert(dev_open == io_ptr->state);
	tcpptr = (d_tcp_struct *)(io_ptr->dev_sp);
	if (io_ptr->dollar.x && (TCP_WRITE == tcpptr->lastop))
	{	/* switching from write to read */
#ifdef C9A06001531
		/* pending change request C9A06-001531 */
		if (!io_ptr->dollar.za)
			iotcp_wteol(1, io_ptr);
#endif
		io_ptr->dollar.x = 0;
	}
	tcpptr->lastop = TCP_READ;
	ret = TRUE;
	timer_id = (TID)iotcp_readfl;
	out_of_time = FALSE;
	time_for_read.at_sec = ((0 == timeout) ? 0 : 1);
	time_for_read.at_usec = 0;
	if (NO_M_TIMEOUT == timeout)
	{
		timed = FALSE;
		msec_timeout = NO_M_TIMEOUT;
	} else
	{
		timed = TRUE;
		msec_timeout = timeout2msec(timeout);
		if (msec_timeout > 0)
		{	/* there is time to wait */
#ifdef UNIX
			/* set blocking I/O */
			FCNTL2(tcpptr->socket, F_GETFL, flags);
			if (flags < 0)
			{
				save_errno = errno;
				errptr = (char *)STRERROR(errno);
				rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"),
						save_errno, LEN_AND_STR(errptr));
			}
			FCNTL3(tcpptr->socket, F_SETFL, flags & (~(O_NDELAY | O_NONBLOCK)), fcntl_res);
			if (fcntl_res < 0)
			{
				save_errno = errno;
				errptr = (char *)STRERROR(errno);
				rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"),
						save_errno, LEN_AND_STR(errptr));
			}
#endif
			sys_get_curr_time(&cur_time);
			add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
			start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL);
		} else
			out_of_time = TRUE;
	}
	for (i = 0, status = 0; status >= 0; )
	{
		FD_ZERO(&tcp_fd);
		FD_SET(tcpptr->socket, &tcp_fd);
		assert(0 != FD_ISSET(tcpptr->socket, &tcp_fd));
		assert(((1 == time_for_read.at_sec) || (0 == time_for_read.at_sec)) && (0 == time_for_read.at_usec));
		/*
		 * the check for EINTR below is valid and should not be converted to an EINTR
		 * wrapper macro, since it might be a timeout.
		 */
		lcl_time_for_read = time_for_read;
		status = tcp_routines.aa_select(tcpptr->socket + 1, (void *)(&tcp_fd), (void *)0, (void *)0,
							&lcl_time_for_read);
		if (status > 0)
		{
			status = tcp_routines.aa_recv(tcpptr->socket, (char *)(stringpool.free +  i), width - i, 0);
			if ((0 == status) || ((-1 == status) && (ECONNRESET == errno || EPIPE == errno || EINVAL == errno)))
			{ /* lost connection. */
				if (0 == status)
					errno = ECONNRESET;
				real_errno = errno;
				status = -2;
				break;
			}

		}
		if (status < 0)
		{
			if (EINTR == errno && FALSE == out_of_time)
			{	/* interrupted by a signal which is not OUR timer, continue looping */
				status = 0;
			} else
				real_errno = errno;
		} else
			real_errno = 0;
		if (outofband)
			break;
		if (timed)
		{
			if (msec_timeout > 0)
			{
				sys_get_curr_time(&cur_time);
				cur_time = sub_abs_time(&end_time, &cur_time);
				if (cur_time.at_sec <= 0)
				{
					out_of_time = TRUE;
					cancel_timer(timer_id);
					if (status > 0)
						i += status;
					break;
				}
			} else
			{
				if (status > 0)
					i += status;
				break;
			}
		}
		if (0 > status)
			break;
		i += status;
		if ((vari && (0 != i)) || (i >= width))
			break;
	}
	if (EINTR == real_errno)
		status = 0;	/* don't treat a <CTRL-C> or timeout as an error */
	if (timed)
	{
		if (0 == msec_timeout)
		{
			if (0 == status)
				ret = FALSE;
		} else
		{
#ifdef UNIX
			real_errno = errno;
			FCNTL3(tcpptr->socket, F_SETFL, flags, fcntl_res);
			if (fcntl_res < 0)
			{
				save_errno = errno;
				errptr = (char *)STRERROR(errno);
				rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"),
					  	save_errno, LEN_AND_STR(errptr));
			}
			errno = real_errno;
#endif
			if (out_of_time && (i < width))
				ret = FALSE;
			else
				cancel_timer(timer_id);
		}
	}
	if (i > 0)
	{	/* there's somthing to return */
		v->str.len = i;
		v->str.addr = (char *)stringpool.free;
		if (((io_ptr->dollar.x += i) >= io_ptr->width) && (TRUE == io_ptr->wrap))
		{
			io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width);
			if (0 != io_ptr->length)
				io_ptr->dollar.y %= io_ptr->length;
			io_ptr->dollar.x %= io_ptr->width;
		}
	} else
		v->str.len = 0;
#ifdef DEBUG_TCP
	PRINTF("%s <<<\n", __FILE__);
#endif
	len = sizeof("1,") - 1;
	if (status >= 0)
	{	/* no real problems */
		io_ptr->dollar.za = 0;
/*	the handling of urgent data doesn't work and never has, the design should be changed to use a /URGENT controlnmemonic
 *	because there is really only one character available at a time
		zero.at_sec = zero.at_usec = 0;
		FD_ZERO(&tcp_fd);
		FD_SET(tcpptr->socket, &tcp_fd);
		if (tcp_routines.aa_select(tcpptr->socket + 1, (void *)(tcpptr->urgent ? &tcp_fd : 0), (void *)0,
								(void *)(tcpptr->urgent ? 0 : &tcp_fd), &zero) > 0)
		{
			memcpy(tcpptr->dollar_device, "1,", len);
			if (tcpptr->urgent)
			{
				memcpy(&tcpptr->dollar_device[len], "No ",sizeof("No "));
				len += sizeof("No ") - 1;
			}
			memcpy(&tcpptr->dollar_device[len], "Urgent Data", sizeof("Urgent Data"));
		} else
*/
			memcpy(tcpptr->dollar_device, "0", sizeof("0"));
	} else
	{	/* there's a significant problem */
		if (0 == i)
			io_ptr->dollar.x = 0;
		io_ptr->dollar.za = 9;
		memcpy(tcpptr->dollar_device, "1,", len);
		errptr = (char *)STRERROR(errno);
		errlen = STRLEN(errptr);
		memcpy(&tcpptr->dollar_device[len], errptr, errlen);
		if (io_ptr->dollar.zeof || -1 == status || 0 < io_ptr->error_handler.len)
		{
			io_ptr->dollar.zeof = TRUE;
			rts_error(VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr);
		} else
			io_ptr->dollar.zeof = TRUE;
	}
	return (ret);
}