+++ /dev/null
-/*
-
- silcfdstream.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2005 - 2007 Pekka Riikonen
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
-*/
-
-#include "silc.h"
-
-/************************** Types and definitions ***************************/
-
-#define SILC_IS_FD_STREAM(s) (s->ops == &silc_fd_stream_ops)
-
-const SilcStreamOps silc_fd_stream_ops;
-
-/* FD stream context */
-typedef struct {
- const SilcStreamOps *ops;
- SilcStack stack;
- SilcSchedule schedule;
- SilcStreamNotifier notifier;
- void *notifier_context;
- int fd1;
- int fd2;
-} *SilcFDStream;
-
-
-/************************ Static utility functions **************************/
-
-/* The IO process callback that calls the notifier callback to upper layer. */
-
-SILC_TASK_CALLBACK(silc_fd_stream_io)
-{
- SilcFDStream stream = context;
-
- if (!stream->notifier)
- return;
-
- switch (type) {
- case SILC_TASK_READ:
- stream->notifier(stream, SILC_STREAM_CAN_READ, stream->notifier_context);
- break;
-
- case SILC_TASK_WRITE:
- stream->notifier(stream, SILC_STREAM_CAN_WRITE, stream->notifier_context);
- break;
-
- default:
- break;
- }
-}
-
-
-/****************************** Public API **********************************/
-
-/* Create file descriptor stream */
-
-SilcStream silc_fd_stream_create(int fd, SilcStack stack)
-{
- if (fd < 1) {
- silc_set_errno_reason(SILC_ERR_BAD_FD, "Bad file descriptor %d", fd);
- return NULL;
- }
- return silc_fd_stream_create2(fd, 0, stack);
-}
-
-/* Create stream with two file descriptors */
-
-SilcStream silc_fd_stream_create2(int read_fd, int write_fd, SilcStack stack)
-{
- SilcFDStream stream;
-
- if (stack)
- stack = silc_stack_alloc(0, stack);
-
- stream = silc_scalloc(stack, 1, sizeof(*stream));
- if (!stream) {
- silc_stack_free(stack);
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Creating new fd stream %p", stream));
-
- stream->ops = &silc_fd_stream_ops;
- stream->fd1 = read_fd;
- stream->fd2 = write_fd;
- stream->stack = stack;
-
- return stream;
-}
-
-/* Create by opening file */
-
-SilcStream silc_fd_stream_file(const char *filename, SilcBool reading,
- SilcBool writing, SilcStack stack)
-{
- const char *read_file = NULL, *write_file = NULL;
-
- if (!filename) {
- silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
- return NULL;
- }
-
- if (writing)
- write_file = filename;
- if (reading)
- read_file = filename;
-
- return silc_fd_stream_file2(read_file, write_file, stack);
-}
-
-/* Create by opening two files */
-
-SilcStream silc_fd_stream_file2(const char *read_file, const char *write_file,
- SilcStack stack)
-{
- SilcStream stream;
- int fd1 = 0, fd2 = 0;
-
- SILC_LOG_DEBUG(("Creating new fd stream for reading `%s' and writing `%s'",
- read_file ? read_file : "(none)",
- write_file ? write_file : "(none)"));
-
- if (write_file) {
- fd2 = silc_file_open(write_file, O_CREAT | O_WRONLY);
- if (fd2 < 0) {
- silc_file_close(fd1);
- return NULL;
- }
- }
-
- if (read_file) {
- fd1 = silc_file_open(read_file, O_RDONLY);
- if (fd1 < 0)
- return NULL;
- }
-
- stream = silc_fd_stream_create2(fd1, fd2, stack);
- if (!stream) {
- silc_file_close(fd1);
- silc_file_close(fd2);
- }
-
- return stream;
-}
-
-/* Return fds */
-
-SilcBool silc_fd_stream_get_info(SilcStream stream, int *read_fd,
- int *write_fd)
-{
- SilcFDStream fd_stream = stream;
-
- if (!SILC_IS_FD_STREAM(fd_stream))
- return FALSE;
-
- if (read_fd)
- *read_fd = fd_stream->fd1;
- if (write_fd)
- *write_fd = fd_stream->fd2;
-
- return TRUE;
-}
-
-/* Read */
-
-int silc_fd_stream_read(SilcStream stream, unsigned char *buf,
- SilcUInt32 buf_len)
-{
- SilcFDStream fd_stream = stream;
- int len = 0;
-
- if (!fd_stream->notifier)
- return -2;
-
- SILC_LOG_DEBUG(("Reading data from fd %d", fd_stream->fd1));
-
- len = silc_file_read(fd_stream->fd1, buf, buf_len);
- if (len < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
- silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd1,
- SILC_TASK_READ, FALSE);
- silc_set_errno_posix(errno);
- return -1;
- }
- SILC_LOG_DEBUG(("Cannot read from fd: %d:%s",
- fd_stream->fd1, strerror(errno)));
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
- silc_set_errno_posix(errno);
- return -2;
- }
-
- SILC_LOG_DEBUG(("Read %d bytes", len));
-
- if (!len)
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
-
- return len;
-}
-
-/* Write */
-
-int silc_fd_stream_write(SilcStream stream, const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcFDStream fd_stream = stream;
- int ret;
-
- if (!fd_stream->notifier)
- return -2;
-
- SILC_LOG_DEBUG(("Writing data to fd %d", fd_stream->fd2));
-
- ret = silc_file_write(fd_stream->fd2, data, data_len);
- if (ret < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
- silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd2,
- SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
- silc_set_errno_posix(errno);
- return -1;
- }
- SILC_LOG_DEBUG(("Cannot write to fd: %s", strerror(errno)));
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
- silc_set_errno_posix(errno);
- return -2;
- }
-
- SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
-
- if (fd_stream->fd1 == fd_stream->fd2)
- silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd2,
- SILC_TASK_READ, FALSE);
- else
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
-
- return ret;
-}
-
-/* Close stream */
-
-SilcBool silc_fd_stream_close(SilcStream stream)
-{
- SilcFDStream fd_stream = stream;
-
- if (fd_stream->fd1 > 0) {
- silc_file_close(fd_stream->fd1);
- if (fd_stream->schedule) {
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
- silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd1);
- }
- }
- if (fd_stream->fd2 > 0 && fd_stream->fd2 != fd_stream->fd1) {
- silc_file_close(fd_stream->fd2);
- if (fd_stream->schedule) {
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
- silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2);
- }
- }
-
- return TRUE;
-}
-
-/* Destroy stream */
-
-void silc_fd_stream_destroy(SilcStream stream)
-{
- SilcFDStream fd_stream = stream;
- SilcStack stack = fd_stream->stack;
-
- silc_fd_stream_close(stream);
- silc_sfree(stack, stream);
- silc_stack_free(stack);
-}
-
-/* Sets stream notification callback for the stream */
-
-SilcBool silc_fd_stream_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context)
-{
- SilcFDStream fd_stream = stream;
-
- SILC_LOG_DEBUG(("Setting stream notifier callback"));
-
- fd_stream->notifier = callback;
- fd_stream->notifier_context = context;
- fd_stream->schedule = schedule;
-
- /* Schedule the file descriptors */
- if (schedule) {
- if (fd_stream->fd2 > 0) {
- silc_schedule_task_add_fd(schedule, fd_stream->fd2,
- silc_fd_stream_io, stream);
- silc_file_set_nonblock(fd_stream->fd2);
- }
- if (fd_stream->fd1 > 0) {
- silc_schedule_task_add_fd(schedule, fd_stream->fd1,
- silc_fd_stream_io, stream);
- silc_schedule_set_listen_fd(schedule, fd_stream->fd1,
- SILC_TASK_READ, FALSE);
- silc_file_set_nonblock(fd_stream->fd1);
- if (fd_stream->fd2 < 1)
- fd_stream->fd2 = fd_stream->fd1;
- }
- } else {
- if (fd_stream->schedule) {
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
- silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
- silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd1);
- silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2);
- }
- }
-
- return TRUE;
-}
-
-/* Return schedule */
-
-SilcSchedule silc_fd_stream_get_schedule(SilcStream stream)
-{
- SilcFDStream fd_stream = stream;
- return fd_stream->schedule;
-}
-
-/* File descriptor stream operations */
-const SilcStreamOps silc_fd_stream_ops =
-{
- silc_fd_stream_read,
- silc_fd_stream_write,
- silc_fd_stream_close,
- silc_fd_stream_destroy,
- silc_fd_stream_notifier,
- silc_fd_stream_get_schedule
-};