X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcfdstream.c;h=ea043f2bec1b57945e7119b77bcde8e1ff0f3139;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=d707e59a326029d073e220b62a4f11dd1c8fd97c;hpb=cb7c2ffa5dbe4332ca22ddb46b0517aadbf49714;p=silc.git diff --git a/lib/silcutil/silcfdstream.c b/lib/silcutil/silcfdstream.c index d707e59a..ea043f2b 100644 --- a/lib/silcutil/silcfdstream.c +++ b/lib/silcutil/silcfdstream.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2005 Pekka Riikonen + 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 @@ -17,7 +17,9 @@ */ -#include "silcincludes.h" +#include "silc.h" + +/************************** Types and definitions ***************************/ #define SILC_IS_FD_STREAM(s) (s->ops == &silc_fd_stream_ops) @@ -26,14 +28,17 @@ 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; - int error; } *SilcFDStream; + +/************************ Static utility functions **************************/ + /* The IO process callback that calls the notifier callback to upper layer. */ SILC_TASK_CALLBACK(silc_fd_stream_io) @@ -44,93 +49,117 @@ SILC_TASK_CALLBACK(silc_fd_stream_io) return; switch (type) { - case SILC_TASK_WRITE: - stream->notifier(stream, SILC_STREAM_CAN_WRITE, stream->notifier_context); - break; - 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, SilcSchedule schedule) +SilcStream silc_fd_stream_create(int fd, SilcStack stack) { - if (fd < 1) + 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, schedule); + } + 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, - SilcSchedule schedule) +SilcStream silc_fd_stream_create2(int read_fd, int write_fd, SilcStack stack) { SilcFDStream stream; - if (read_fd < 1) - return NULL; + if (stack) + stack = silc_stack_alloc(0, stack); - stream = silc_calloc(1, sizeof(*stream)); - if (!stream) + 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->schedule = schedule; stream->fd1 = read_fd; stream->fd2 = write_fd; - - /* Schedule the file descriptors */ - if (write_fd > 0) { - silc_schedule_task_add_fd(schedule, write_fd, silc_fd_stream_io, stream); - silc_file_set_nonblock(write_fd); - } - if (read_fd > 0) { - silc_schedule_task_add_fd(schedule, read_fd, silc_fd_stream_io, stream); - silc_schedule_set_listen_fd(schedule, read_fd, SILC_TASK_READ, FALSE); - silc_file_set_nonblock(read_fd); - if (write_fd < 1) - stream->fd2 = stream->fd1; - } + stream->stack = stack; return stream; } /* Create by opening file */ -SilcStream silc_fd_stream_file(const char *filename, - SilcBool reading, SilcBool writing, - SilcSchedule schedule) +SilcStream silc_fd_stream_file(const char *filename, SilcBool reading, + SilcBool writing, SilcStack stack) { - int fd, flags = 0; + const char *read_file = NULL, *write_file = NULL; - if (!filename) + if (!filename) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); return NULL; + } - if (reading) - flags |= O_RDONLY; if (writing) - flags |= O_WRONLY; - if (reading && writing) - flags |= O_RDWR; + write_file = filename; + if (reading) + read_file = filename; - fd = silc_file_open(filename, flags); - if (fd < 0) - return NULL; + 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; + } - return silc_fd_stream_create(fd, schedule); + 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) +SilcBool silc_fd_stream_get_info(SilcStream stream, int *read_fd, + int *write_fd) { SilcFDStream fd_stream = stream; @@ -145,18 +174,6 @@ SilcBool silc_fd_stream_get_info(SilcStream stream, int *read_fd, int *write_fd) return TRUE; } -/* Return errno */ - -int silc_fd_stream_get_error(SilcStream stream) -{ - SilcFDStream fd_stream = stream; - - if (!SILC_IS_FD_STREAM(fd_stream)) - return 0; - - return fd_stream->error; -} - /* Read */ int silc_fd_stream_read(SilcStream stream, unsigned char *buf, @@ -165,7 +182,7 @@ int silc_fd_stream_read(SilcStream stream, unsigned char *buf, SilcFDStream fd_stream = stream; int len = 0; - if (!SILC_IS_FD_STREAM(fd_stream)) + if (!fd_stream->notifier) return -2; SILC_LOG_DEBUG(("Reading data from fd %d", fd_stream->fd1)); @@ -176,12 +193,13 @@ int silc_fd_stream_read(SilcStream stream, unsigned char *buf, 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); - fd_stream->error = errno; + silc_set_errno_posix(errno); return -2; } @@ -201,7 +219,7 @@ int silc_fd_stream_write(SilcStream stream, const unsigned char *data, SilcFDStream fd_stream = stream; int ret; - if (!SILC_IS_FD_STREAM(fd_stream)) + if (!fd_stream->notifier) return -2; SILC_LOG_DEBUG(("Writing data to fd %d", fd_stream->fd2)); @@ -212,11 +230,12 @@ int silc_fd_stream_write(SilcStream stream, const unsigned char *data, 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); - fd_stream->error = errno; + silc_set_errno_posix(errno); return -2; } @@ -237,16 +256,19 @@ SilcBool silc_fd_stream_close(SilcStream stream) { SilcFDStream fd_stream = stream; - if (!SILC_IS_FD_STREAM(fd_stream)) - return FALSE; - if (fd_stream->fd1 > 0) { silc_file_close(fd_stream->fd1); - silc_schedule_unset_listen_fd(fd_stream->schedule, 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); - silc_schedule_unset_listen_fd(fd_stream->schedule, 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; @@ -257,31 +279,62 @@ SilcBool silc_fd_stream_close(SilcStream stream) void silc_fd_stream_destroy(SilcStream stream) { SilcFDStream fd_stream = stream; - - if (!SILC_IS_FD_STREAM(fd_stream)) - return; + SilcStack stack = fd_stream->stack; silc_fd_stream_close(stream); - silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd1); - silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2); - silc_free(stream); + silc_sfree(stack, stream); + silc_stack_free(stack); } /* Sets stream notification callback for the stream */ -void silc_fd_stream_notifier(SilcStream stream, - SilcStreamNotifier callback, - void *context) +SilcBool silc_fd_stream_notifier(SilcStream stream, + SilcSchedule schedule, + SilcStreamNotifier callback, + void *context) { SilcFDStream fd_stream = stream; - if (!SILC_IS_FD_STREAM(fd_stream)) - return; - 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 */ @@ -292,4 +345,5 @@ const SilcStreamOps silc_fd_stream_ops = silc_fd_stream_close, silc_fd_stream_destroy, silc_fd_stream_notifier, + silc_fd_stream_get_schedule };