/*
 * Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers.
 *      All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: stthreadsio.c,v 1.25 2006/07/16 02:07:40 ca Exp $")
#include "sm/error.h"
#include "fcntl.h"
#include "sm/memops.h"
#include "sm/stat.h"
#include "sm/time.h"
#include "sm/heap.h"
#include "sm/assert.h"
#include "sm/varargs.h"
#include "sm/io.h"
#include "sm/fdset.h"
#include "sm/stthreads.h"
#include "io-int.h"
#include "statethreads/st.h"

static read_F sm_thrread;
static write_F sm_thrwrite;
#if 0
static sm_ret_T
sm_thrssm_ret_T(sm_file_T *fp, off_t offset, int whence);
#endif
static close_F	sm_thrclose;
static sm_ret_T
sm_thrgetmode(sm_file_T *fp, int *mode);
static getinfo_F sm_thrgetinfo;
static setinfo_F sm_thrsetinfo;
static open_F	sm_thrfdopen;
static seek_F	sm_thrseek;

static open_F sm_thrnetopen;
#if 0
close_F	sm_thrnetclose;
#endif

sm_stream_T SmStThrIO =
	SM_STREAM_STRUCT(sm_thrfdopen, sm_thrclose, sm_thrread, sm_thrwrite, \
		NULL, NULL, sm_thrseek, sm_thrgetinfo, sm_thrsetinfo);

sm_stream_T SmStThrNetIO =
	SM_STREAM_STRUCT(sm_thrnetopen, sm_thrclose, sm_thrread, sm_thrwrite, \
		NULL, NULL, sm_thrseek, sm_thrgetinfo, sm_thrsetinfo);


#define f_netfd(fp)	((st_netfd_t) f_cookie(fp))
#define assign_f_netfd(fp, netfd)	f_cookie(fp) = (void *) (netfd)

/*
**  SM_THRREAD -- read from the file
**
**	Parameters:
**		fp -- file pointer to read from
**		buf -- location to place read data
**		n -- number of bytes to read
**		bytesread -- number of bytes read (output)
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
sm_thrread(sm_file_T *fp, uchar *buf, size_t n, ssize_t *bytesread)
{
	ssize_t ret;

	do
	{
		errno = 0;
		ret = st_read(f_netfd(*fp), buf, n, SEC2USEC(fp->f_timeout));
	} while (ret == -1 && errno == EINTR);
	if (ret == -1)
	{
		int e;

		e = errno;
		*bytesread = 0;
		if (E_IS_TEMP(e))
			return sm_error_temp(SM_EM_STTHRIO, e);
		return sm_error_perm(SM_EM_STTHRIO, e);
	}
	*bytesread = ret;
	return SM_SUCCESS;
}

/*
**  SM_THRWRITE -- write to the file
**
**	Parameters:
**		fp -- file pointer ro write to
**		buf -- location of data to be written
**		n -- number of bytes to write
**		byteswritten -- number of bytes written (output)
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
sm_thrwrite(sm_file_T *fp, const uchar *buf, size_t n, ssize_t *byteswritten)
{
	ssize_t ret;

	do
	{
		errno = 0;
		ret = st_write(f_netfd(*fp), buf, n, SEC2USEC(fp->f_timeout));
	} while (ret == -1 && errno == EINTR);
	if (ret == -1)
	{
		int e;

		e = errno;
		*byteswritten = 0;
		if (E_IS_TEMP(e))
			return sm_error_temp(SM_EM_STTHRIO, e);
		return sm_error_perm(SM_EM_STTHRIO, e);
	}
	*byteswritten = ret;
	return SM_SUCCESS;
}

/*
**  SM_THRSEEK -- set the file offset position
**
**	Parmeters:
**		fp -- file pointer to position
**		offset -- how far to position from "base" (set by 'whence')
**		whence -- indicates where the "base" of the 'offset' to start
**
**	Results:
**		sm_error_perm(SM_EM_STTHRIO, ESPIPE)
*/

/* ARGSUSED0 */
static sm_ret_T
sm_thrseek(sm_file_T *fp, off_t offset, int whence)
{
	return sm_error_perm(SM_EM_STTHRIO, ESPIPE);
}

/*
**  SM_THRCLOSE -- close the file
**
**	Parameters:
**		fp -- the file pointer to close
**		flags -- ignored
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
sm_thrclose(sm_file_T *fp, int flags)
{
	int r;

	r = st_netfd_close(f_netfd(*fp));
	if (r == -1)
		return sm_error_perm(SM_EM_STTHRIO, errno);
	return SM_SUCCESS;
}

/*
**  SM_THRSETMODE -- set the access mode for the file
**	Called by sm_stdsetinfo().
**	XXX do we really want to allow changing the mode?
**
**	Parameters:
**		fp -- file pointer
**		mode -- new mode to set the file access to
**
**	Results:
**		Success: 0 (zero);
**		Failure: -1 and sets errno
*/

static sm_ret_T
sm_thrsetmode(sm_file_T *fp, const int *mode)
{
	int flags = 0;

	switch (*mode)
	{
	  case SM_IO_RDWR:
		flags |= SMRW;
		break;
	  case SM_IO_RDONLY:
		flags |= SMRD;
		break;
	  case SM_IO_WRONLY:
		flags |= SMWR;
		break;
	  case SM_IO_APPEND:
	  default:
		return sm_error_perm(SM_EM_STTHRIO, EINVAL);
	}
	f_flags(*fp) = f_flags(*fp) & ~SMMODEMASK;
	f_flags(*fp) |= flags;
	return SM_SUCCESS;
}

/*
**  SM_THRGETMODE -- for getinfo determine open mode
**
**  Called by sm_thrgetinfo().
**
**	Parameters:
**		fp -- the file mode being determined
**		mode -- internal mode to map to external value
**
**	Results:
**		Failure: -1 and sets errno
**		Success: external mode value
*/

static sm_ret_T
sm_thrgetmode(sm_file_T *fp, int *mode)
{
	switch (f_flags(*fp) & SMMODEMASK)
	{
	  case SMRW:
		*mode = SM_IO_RDWR;
		break;
	  case SMRD:
		*mode = SM_IO_RDONLY;
		break;
	  case SMWR:
		*mode = SM_IO_WRONLY;
		break;
	  default:
		return sm_error_perm(SM_EM_STTHRIO, EINVAL);
	}
	return SM_SUCCESS;
}

/*
**  SM_THRSETINFO -- set/modify information for a file
**
**	Parameters:
**		fp -- file to set info for
**		what -- type of info to set
**		valp -- location of data used for setting
**
**	Returns:
**		usual sm_error code.
*/

static sm_ret_T
sm_thrsetinfo(sm_file_T *fp, int what, void *valp)
{
	switch (what)
	{
	  case SM_IO_WHAT_MODE:
		return sm_thrsetmode(fp, (const int *)valp);

	  default:
		return sm_error_perm(SM_EM_STTHRIO, EINVAL);
	}
}

/*
**  SM_GETINFO -- get information about the open file
**
**	Parameters:
**		fp -- file to get info for
**		what -- type of info to get
**		valp -- location to place found info
**
**	Returns:
**		Success: may or may not place info in 'valp' depending
**			on 'what' value, and returns values >=0. Return
**			value may be the obtained info
**		Failure: usual sm_error code.
*/

static sm_ret_T
sm_thrgetinfo(sm_file_T *fp, int what, void *valp)
{
	switch (what)
	{
	  case SM_IO_WHAT_MODE:
		return sm_thrgetmode(fp, (int *)valp);

	  case SM_IO_WHAT_FD:
		return f_fd(*fp);

#if 0
	  case SM_IO_WHAT_NETFD:
		valp = f_netfd(*fp);
		return SM_SUCCESS;
#endif /* 0 */

		/* XXX check state-threads code! */
	  case SM_IO_IS_READABLE:
		if (st_netfd_poll(f_netfd(*fp), POLLIN, (st_utime_t) 0) == 0)
			return 1;
		return 0;

	  default:
		return sm_error_perm(SM_EM_STTHRIO, EINVAL);
	}
}

/*
**  SM_THRFDOPEN -- open file by primitive 'fd' rather than pathname
**
**	I/O function to handle fdopen() stdio equivalence. The rest of
**	the functions are the same as the sm_stdopen() above.
**
**	Parameters:
**		fp -- the file pointer to be associated with the open
**		name -- the primitive file descriptor for association
**		flags -- indicates type of access methods
**
**	Results:
**		usual sm_error code.
*/

/* ARGSUSED3 */
static sm_ret_T
sm_thrfdopen(sm_file_T *fp, const void *info, int flags, va_list ap)
{
	int fd;
	st_netfd_t netfd;

	fd = *((const int *) info);
#if 0
	switch (flags)
	{
	  case SM_IO_RDWR:
		oflags = O_RDWR | O_CREAT;
		break;
	  case SM_IO_RDONLY:
		oflags = O_RDONLY;
		break;
	  case SM_IO_WRONLY:
		oflags = O_WRONLY | O_CREAT | O_TRUNC;
		break;
	  default:
		return sm_error_perm(SM_EM_STTHRIO, EINVAL);
	}
#endif /* 0 */

	netfd = st_netfd_open(fd);
	if (netfd == NULL)
		return sm_error_perm(SM_EM_STTHRIO, errno);	/* ??? temp? */
	f_fd(*fp) = fd;
	assign_f_netfd(*fp, netfd);
	return SM_SUCCESS;
}

/*
**  SM_THRNETOPEN -- open file by netfd 'fd' rather than pathname
**
**	Parameters:
**		fp -- the file pointer to be associated with the open
**		name -- the primitive file descriptor for association
**		flags -- indicates type of access methods
**
**	Results:
**		usual sm_error code.
*/

/* ARGSUSED3 */
static sm_ret_T
sm_thrnetopen(sm_file_T *fp, const void *info, int flags, va_list ap)
{
	st_netfd_t netfd;

	netfd = *((st_netfd_t *) info);
	f_fd(*fp) = st_netfd_fileno(netfd);
	assign_f_netfd(*fp, netfd);
	return SM_SUCCESS;
}

#if 0
/*
**  SM_THRCLOSE -- close the file
**
**	Parameters:
**		fp -- the file pointer to close
**		flags -- ignored
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
sm_thrnetclose(sm_file_T *fp, int flags)
{
	return SM_SUCCESS;
}
#endif /* 0 */


syntax highlighted by Code2HTML, v. 0.9.1