5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2005 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 /************************** Types and definitions ***************************/
24 #define SILC_IS_FD_STREAM(s) (s->ops == &silc_fd_stream_ops)
26 const SilcStreamOps silc_fd_stream_ops;
28 /* FD stream context */
30 const SilcStreamOps *ops;
31 SilcSchedule schedule;
32 SilcStreamNotifier notifier;
33 void *notifier_context;
40 /************************ Static utility functions **************************/
42 /* The IO process callback that calls the notifier callback to upper layer. */
44 SILC_TASK_CALLBACK(silc_fd_stream_io)
46 SilcFDStream stream = context;
48 if (!stream->notifier)
53 stream->notifier(stream, SILC_STREAM_CAN_READ, stream->notifier_context);
57 stream->notifier(stream, SILC_STREAM_CAN_WRITE, stream->notifier_context);
66 /****************************** Public API **********************************/
68 /* Create file descriptor stream */
70 SilcStream silc_fd_stream_create(int fd)
74 return silc_fd_stream_create2(fd, 0);
77 /* Create stream with two file descriptors */
79 SilcStream silc_fd_stream_create2(int read_fd, int write_fd)
86 stream = silc_calloc(1, sizeof(*stream));
90 SILC_LOG_DEBUG(("Creating new fd stream %p", stream));
92 stream->ops = &silc_fd_stream_ops;
93 stream->fd1 = read_fd;
94 stream->fd2 = write_fd;
99 /* Create by opening file */
101 SilcStream silc_fd_stream_file(const char *filename,
102 SilcBool reading, SilcBool writing)
110 SILC_LOG_DEBUG(("Creating new fd stream for file `%s'", filename));
115 flags |= O_CREAT | O_WRONLY;
116 if (reading && writing)
117 flags = O_CREAT | O_RDWR;
119 fd = silc_file_open(filename, flags);
123 stream = silc_fd_stream_create(fd);
132 SilcBool silc_fd_stream_get_info(SilcStream stream, int *read_fd,
135 SilcFDStream fd_stream = stream;
137 if (!SILC_IS_FD_STREAM(fd_stream))
141 *read_fd = fd_stream->fd1;
143 *write_fd = fd_stream->fd2;
150 int silc_fd_stream_get_error(SilcStream stream)
152 SilcFDStream fd_stream = stream;
154 if (!SILC_IS_FD_STREAM(fd_stream))
157 return fd_stream->error;
162 int silc_fd_stream_read(SilcStream stream, unsigned char *buf,
165 SilcFDStream fd_stream = stream;
168 if (!fd_stream->notifier)
171 SILC_LOG_DEBUG(("Reading data from fd %d", fd_stream->fd1));
173 len = silc_file_read(fd_stream->fd1, buf, buf_len);
175 if (errno == EAGAIN || errno == EINTR) {
176 SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
177 silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd1,
178 SILC_TASK_READ, FALSE);
181 SILC_LOG_DEBUG(("Cannot read from fd: %d:%s",
182 fd_stream->fd1, strerror(errno)));
183 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
184 fd_stream->error = errno;
188 SILC_LOG_DEBUG(("Read %d bytes", len));
191 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
198 int silc_fd_stream_write(SilcStream stream, const unsigned char *data,
201 SilcFDStream fd_stream = stream;
204 if (!fd_stream->notifier)
207 SILC_LOG_DEBUG(("Writing data to fd %d", fd_stream->fd2));
209 ret = silc_file_write(fd_stream->fd2, data, data_len);
211 if (errno == EAGAIN || errno == EINTR) {
212 SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
213 silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd2,
214 SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
217 SILC_LOG_DEBUG(("Cannot write to fd: %s", strerror(errno)));
218 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
219 fd_stream->error = errno;
223 SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
225 if (fd_stream->fd1 == fd_stream->fd2)
226 silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd2,
227 SILC_TASK_READ, FALSE);
229 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
236 SilcBool silc_fd_stream_close(SilcStream stream)
238 SilcFDStream fd_stream = stream;
240 if (fd_stream->fd1 > 0) {
241 silc_file_close(fd_stream->fd1);
242 if (fd_stream->schedule) {
243 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
244 silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd1);
247 if (fd_stream->fd2 > 0 && fd_stream->fd2 != fd_stream->fd1) {
248 silc_file_close(fd_stream->fd2);
249 if (fd_stream->schedule) {
250 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
251 silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2);
260 void silc_fd_stream_destroy(SilcStream stream)
262 silc_fd_stream_close(stream);
266 /* Sets stream notification callback for the stream */
268 SilcBool silc_fd_stream_notifier(SilcStream stream,
269 SilcSchedule schedule,
270 SilcStreamNotifier callback,
273 SilcFDStream fd_stream = stream;
275 SILC_LOG_DEBUG(("Setting stream notifier callback"));
277 fd_stream->notifier = callback;
278 fd_stream->notifier_context = context;
279 fd_stream->schedule = schedule;
281 /* Schedule the file descriptors */
283 if (fd_stream->fd2 > 0) {
284 silc_schedule_task_add_fd(schedule, fd_stream->fd2,
285 silc_fd_stream_io, stream);
286 silc_file_set_nonblock(fd_stream->fd2);
288 if (fd_stream->fd1 > 0) {
289 silc_schedule_task_add_fd(schedule, fd_stream->fd1,
290 silc_fd_stream_io, stream);
291 silc_schedule_set_listen_fd(schedule, fd_stream->fd1,
292 SILC_TASK_READ, FALSE);
293 silc_file_set_nonblock(fd_stream->fd1);;
294 if (fd_stream->fd2 < 1)
295 fd_stream->fd2 = fd_stream->fd1;
298 if (fd_stream->schedule) {
299 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
300 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
301 silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd1);
302 silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2);
309 /* Return schedule */
311 SilcSchedule silc_fd_stream_get_schedule(SilcStream stream)
313 SilcFDStream fd_stream = stream;
314 return fd_stream->schedule;
317 /* File descriptor stream operations */
318 const SilcStreamOps silc_fd_stream_ops =
321 silc_fd_stream_write,
322 silc_fd_stream_close,
323 silc_fd_stream_destroy,
324 silc_fd_stream_notifier,
325 silc_fd_stream_get_schedule