stream.c 3.59 KB
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>

#ifndef WIN32
# include <sys/ioctl.h>
#else
# include <windows.h>
# include <winsock2.h>
#endif

#include <scot/stream.h>
#include <scot/memory.h>
#include <scot/exception.h>
#include <scot/socket.h>
#include <scot/scot_types.h>

#include <scot_common.h>

static
SSIZE_T
scot_read (struct scot_stream * st, SIZE_T count)
{
	switch (st->s_type)
	{
		case (SCOT_STREAM_TYPE_SOCKET):
			return recv (st->handle.sock, st->rbuf, count, 0);
		case (SCOT_STREAM_TYPE_FILE):
		case (SCOT_STREAM_TYPE_PIPE):
		case (SCOT_STREAM_TYPE_INOTIFY):
			return SCOT_FILE_READ (st->handle.file, st->rbuf, count);
	}
}

int
scot_stream_eof (struct scot_stream * st)
{
	/* if there is still data in the buffer we have no eof */
	if (st->rbuf_idx != 0)
		return 0;

	/* try to read data in the buffer */
	st->rbuf_idx = scot_read (st, SCOT_STREAM_BUF_SIZE);

	if (st->rbuf_idx == 0)
		return 1;

	/* if no data was available reset the idx to 0 */
	if (st->rbuf_idx == -1)
		switch (SCOT_ERRNO)
		{
#ifndef WIN32
			case (EAGAIN): st->rbuf_idx = 0; return 0;
#else
			case (WSAECONNRESET):  st->rbuf_idx = 0; return 1;
			case (WSAEWOULDBLOCK): st->rbuf_idx = 0; return 0;
#endif
			default: THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO)));
		}

	return 0;
}

static
SSIZE_T
scot_stream_read_copy_buffers (struct scot_stream * s, char * dest, SIZE_T c)
{
	SSIZE_T ret = 0;

	if (c <= s->rbuf_idx)
	{
		SCOT_MEM_COPY (dest, s->rbuf, c);
		SCOT_MEM_MOVE (s->rbuf, s->rbuf + c, s->rbuf_idx - c);
		s->rbuf_idx -= c;
		ret          = c;
	}
	else
	{
		SCOT_MEM_COPY (dest, s->rbuf, s->rbuf_idx);
		ret         = s->rbuf_idx;
		s->rbuf_idx = 0;
	}

	return ret;
}

static
SSIZE_T
scot_stream_read_buffered (struct scot_stream * st, char * buffer, SIZE_T count)
{
	SSIZE_T ret;
	SIZE_T size = SCOT_STREAM_BUF_SIZE;

	if ((ret = scot_stream_read_copy_buffers (st, buffer, count)) == count)
		return count;

#ifndef WIN32
	if (st->s_type == SCOT_STREAM_TYPE_INOTIFY)
	{
		ioctl (st->handle.file, FIONREAD, &size);
		size = (size <= SCOT_STREAM_BUF_SIZE)?size:SCOT_STREAM_BUF_SIZE;
	}
#endif

	while (ret != count)
	{
		SIZE_T read_c;

		read_c = st->rbuf_idx = scot_read (st, size);

		if (st->rbuf_idx == -1)
			switch (SCOT_ERRNO)
			{
#ifndef WIN32
				case (EAGAIN): st->rbuf_idx = 0; return 0;
#else
				case (WSAECONNRESET):  st->rbuf_idx = 0; return ret;
				case (WSAEWOULDBLOCK): st->rbuf_idx = 0; return 0;
#endif
				default: THROW (EXC (EXC_ERROR, SCOT_ERRNO, strerror (SCOT_ERRNO)));
			}

		ret += scot_stream_read_copy_buffers (st, buffer+ret, count-ret);

		if (read_c != size)
			break;
	}

	return ret;
}

SSIZE_T
scot_stream_read (struct scot_stream * st, char * buffer, SIZE_T count)
{
	return scot_stream_read_buffered (st, buffer, count);
}

SSIZE_T 
scot_stream_write (struct scot_stream * st, char * buffer, SIZE_T count)
{
}

SSIZE_T scot_stream_read_pending  (struct scot_stream * st)
{
	return st->rbuf_idx;
}

SSIZE_T scot_stream_write_pending (struct scot_stream * st)
{
	return st->wbuf_idx;
}

void
scot_stream_flush (struct scot_stream * st)
{
}

int
scot_stream_is_closed (struct scot_stream * st)
{
	return (st!=NULL && st->rbuf_idx==-1)?1:0;
}

void
scot_stream_close (struct scot_stream * st)
{
	switch (st->s_type)
	{
		case (SCOT_STREAM_TYPE_SOCKET):
			SCOT_SOCK_CLOSE (st->handle.sock);
			break;
		default:
#ifndef WIN32
			close (st->handle.file);
#endif
			break;
	}
	SCOT_MEM_ZERO (st->rbuf, SCOT_STREAM_BUF_SIZE);
	SCOT_MEM_ZERO (st->wbuf, SCOT_STREAM_BUF_SIZE);
	st->rbuf_idx = -1;
	st->wbuf_idx = -1;
}

void 
scot_stream_free (struct scot_stream * st)
{
	SCOT_STREAM_FREE (st);
}