5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2005 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 #define SILC_IS_FD_STREAM(s) (s->ops == &silc_fd_stream_ops)
24 const SilcStreamOps silc_fd_stream_ops;
26 /* FD stream context */
28 const SilcStreamOps *ops;
29 SilcSchedule schedule;
30 SilcStreamNotifier notifier;
31 void *notifier_context;
37 /* The IO process callback that calls the notifier callback to upper layer. */
39 SILC_TASK_CALLBACK(silc_fd_stream_io)
41 SilcFDStream stream = context;
43 if (!stream->notifier)
48 stream->notifier(stream, SILC_STREAM_CAN_WRITE, stream->notifier_context);
52 stream->notifier(stream, SILC_STREAM_CAN_READ, stream->notifier_context);
60 /* Create file descriptor stream */
62 SilcStream silc_fd_stream_create(int fd)
66 return silc_fd_stream_create2(fd, 0);
69 /* Create stream with two file descriptors */
71 SilcStream silc_fd_stream_create2(int read_fd, int write_fd)
78 stream = silc_calloc(1, sizeof(*stream));
82 SILC_LOG_DEBUG(("Creating new fd stream %p", stream));
84 stream->ops = &silc_fd_stream_ops;
85 stream->fd1 = read_fd;
86 stream->fd2 = write_fd;
91 /* Create by opening file */
93 SilcStream silc_fd_stream_file(const char *filename,
94 SilcBool reading, SilcBool writing)
104 flags |= O_CREAT | O_WRONLY;
105 if (reading && writing)
106 flags |= O_CREAT | O_RDWR;
108 fd = silc_file_open(filename, flags);
112 return silc_fd_stream_create(fd);
117 SilcBool silc_fd_stream_get_info(SilcStream stream, int *read_fd,
120 SilcFDStream fd_stream = stream;
122 if (!SILC_IS_FD_STREAM(fd_stream))
126 *read_fd = fd_stream->fd1;
128 *write_fd = fd_stream->fd2;
135 int silc_fd_stream_get_error(SilcStream stream)
137 SilcFDStream fd_stream = stream;
139 if (!SILC_IS_FD_STREAM(fd_stream))
142 return fd_stream->error;
147 int silc_fd_stream_read(SilcStream stream, unsigned char *buf,
150 SilcFDStream fd_stream = stream;
153 if (!SILC_IS_FD_STREAM(fd_stream))
155 if (!fd_stream->notifier)
158 SILC_LOG_DEBUG(("Reading data from fd %d", fd_stream->fd1));
160 len = silc_file_read(fd_stream->fd1, buf, buf_len);
162 if (errno == EAGAIN || errno == EINTR) {
163 SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
164 silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd1,
165 SILC_TASK_READ, FALSE);
168 SILC_LOG_DEBUG(("Cannot read from fd: %d:%s",
169 fd_stream->fd1, strerror(errno)));
170 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
171 fd_stream->error = errno;
175 SILC_LOG_DEBUG(("Read %d bytes", len));
178 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
185 int silc_fd_stream_write(SilcStream stream, const unsigned char *data,
188 SilcFDStream fd_stream = stream;
191 if (!SILC_IS_FD_STREAM(fd_stream))
193 if (!fd_stream->notifier)
196 SILC_LOG_DEBUG(("Writing data to fd %d", fd_stream->fd2));
198 ret = silc_file_write(fd_stream->fd2, data, data_len);
200 if (errno == EAGAIN || errno == EINTR) {
201 SILC_LOG_DEBUG(("Could not write immediately, will do it later"));
202 silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd2,
203 SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
206 SILC_LOG_DEBUG(("Cannot write to fd: %s", strerror(errno)));
207 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
208 fd_stream->error = errno;
212 SILC_LOG_DEBUG(("Wrote data %d bytes", ret));
214 if (fd_stream->fd1 == fd_stream->fd2)
215 silc_schedule_set_listen_fd(fd_stream->schedule, fd_stream->fd2,
216 SILC_TASK_READ, FALSE);
218 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
225 SilcBool silc_fd_stream_close(SilcStream stream)
227 SilcFDStream fd_stream = stream;
229 if (!SILC_IS_FD_STREAM(fd_stream))
232 if (fd_stream->fd1 > 0) {
233 silc_file_close(fd_stream->fd1);
234 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
236 if (fd_stream->fd2 > 0 && fd_stream->fd2 != fd_stream->fd1) {
237 silc_file_close(fd_stream->fd2);
238 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
246 void silc_fd_stream_destroy(SilcStream stream)
248 SilcFDStream fd_stream = stream;
250 if (!SILC_IS_FD_STREAM(fd_stream))
253 silc_fd_stream_close(stream);
254 silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd1);
255 silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2);
259 /* Sets stream notification callback for the stream */
261 void silc_fd_stream_notifier(SilcStream stream,
262 SilcSchedule schedule,
263 SilcStreamNotifier callback,
266 SilcFDStream fd_stream = stream;
268 if (!SILC_IS_FD_STREAM(fd_stream))
271 SILC_LOG_DEBUG(("Setting stream notifier callback"));
273 fd_stream->notifier = callback;
274 fd_stream->notifier_context = context;
275 fd_stream->schedule = schedule;
277 /* Schedule the file descriptors */
279 if (fd_stream->fd2 > 0) {
280 silc_schedule_task_add_fd(schedule, fd_stream->fd2,
281 silc_fd_stream_io, stream);
282 silc_file_set_nonblock(fd_stream->fd2);
284 if (fd_stream->fd1 > 0) {
285 silc_schedule_task_add_fd(schedule, fd_stream->fd1,
286 silc_fd_stream_io, stream);
287 silc_schedule_set_listen_fd(schedule, fd_stream->fd1,
288 SILC_TASK_READ, FALSE);
289 silc_file_set_nonblock(fd_stream->fd1);;
290 if (fd_stream->fd2 < 1)
291 fd_stream->fd2 = fd_stream->fd1;
294 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
295 silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
299 /* Return schedule */
301 SilcSchedule silc_fd_stream_get_schedule(SilcStream stream)
303 SilcFDStream fd_stream = stream;
305 if (!SILC_IS_FD_STREAM(fd_stream))
308 return fd_stream->schedule;
311 /* File descriptor stream operations */
312 const SilcStreamOps silc_fd_stream_ops =
315 silc_fd_stream_write,
316 silc_fd_stream_close,
317 silc_fd_stream_destroy,
318 silc_fd_stream_notifier,
319 silc_fd_stream_get_schedule