returns error condition.
Fixed FD task addition when FD task already exists.
if (fd_stream->fd1 > 0) {
silc_file_close(fd_stream->fd1);
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);
+ silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2);
}
return TRUE;
void silc_fd_stream_destroy(SilcStream stream)
{
- SilcFDStream fd_stream = stream;
-
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);
}
/* Sets stream notification callback for the stream */
-void silc_fd_stream_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context)
+SilcBool silc_fd_stream_notifier(SilcStream stream,
+ SilcSchedule schedule,
+ SilcStreamNotifier callback,
+ void *context)
{
SilcFDStream fd_stream = stream;
} else {
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 */
/* Check if fd is already added */
if (silc_unlikely(silc_hash_table_find(schedule->fd_queue,
SILC_32_TO_PTR(fd),
- NULL, (void **)&task)))
- goto out;
+ NULL, (void **)&task))) {
+ if (task->valid) {
+ task = NULL;
+ goto out;
+ }
+
+ /* Remove invalid task. We must have unique fd key to hash table. */
+ silc_schedule_task_remove(schedule, task);
+ }
/* Check max tasks */
if (silc_unlikely(schedule->max_tasks > 0 &&
silc_hash_table_count(schedule->fd_queue) >=
schedule->max_tasks)) {
SILC_LOG_WARNING(("Scheduler task limit reached: cannot add new task"));
+ task = NULL;
goto out;
}
ftask = silc_calloc(1, sizeof(*ftask));
- if (silc_unlikely(!ftask))
+ if (silc_unlikely(!ftask)) {
+ task = NULL;
goto out;
+ }
SILC_LOG_DEBUG(("New fd task %p fd=%d", ftask, fd));
ftask->fd = fd;
/* Add task and schedule it */
- silc_hash_table_add(schedule->fd_queue, SILC_32_TO_PTR(fd), ftask);
- schedule_ops.schedule_fd(schedule, schedule->internal, ftask,
- ftask->events);
+ if (!silc_hash_table_add(schedule->fd_queue, SILC_32_TO_PTR(fd), ftask)) {
+ silc_free(ftask);
+ task = NULL;
+ goto out;
+ }
+ if (!schedule_ops.schedule_fd(schedule, schedule->internal,
+ ftask, ftask->events)) {
+ silc_hash_table_del(schedule->fd_queue, SILC_32_TO_PTR(fd));
+ task = NULL;
+ goto out;
+ }
task = (SilcTask)ftask;
/* fd is unique, so there is only one task with this fd in the table */
if (silc_likely(silc_hash_table_find(schedule->fd_queue,
SILC_32_TO_PTR(fd), NULL,
- (void **)&task)))
+ (void **)&task))) {
+ SILC_LOG_DEBUG(("Deleting task %p", task));
task->valid = FALSE;
+ }
SILC_SCHEDULE_UNLOCK(schedule);
directly if wanted. This can be called multiple times for one file
descriptor to set different iomasks. */
-void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
- SilcTaskEvent mask, SilcBool send_events)
+SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
+ SilcTaskEvent mask, SilcBool send_events)
{
SilcTaskFd task;
if (silc_unlikely(!schedule->valid))
- return;
+ return FALSE;
SILC_SCHEDULE_LOCK(schedule);
if (silc_hash_table_find(schedule->fd_queue, SILC_32_TO_PTR(fd),
NULL, (void **)&task)) {
+ if (!schedule_ops.schedule_fd(schedule, schedule->internal, task, mask)) {
+ SILC_SCHEDULE_UNLOCK(schedule);
+ return FALSE;
+ }
task->events = mask;
- schedule_ops.schedule_fd(schedule, schedule->internal, task, mask);
if (silc_unlikely(send_events) && mask) {
task->revents = mask;
silc_schedule_dispatch_fd(schedule);
}
SILC_SCHEDULE_UNLOCK(schedule);
+
+ return TRUE;
}
-/* Returns the file descriptors current requested event mask. */
+/* Returns the file descriptor's current requested event mask. */
SilcTaskEvent silc_schedule_get_fd_events(SilcSchedule schedule,
SilcUInt32 fd)
* handle. To receive events for the file descriptor set the correct
* request events with silc_schedule_set_listen_fd function.
*
+ * The task will be initially set for SILC_TASK_READ events. Setting that
+ * event immediately after this call returns is not necessary.
+ *
***/
#define silc_schedule_task_add_fd(schedule, fd, callback, context) \
silc_schedule_task_add(schedule, fd, callback, context, 0, 0, SILC_TASK_FD)
*
* SYNOPSIS
*
- * void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
- * SilcTaskEvent mask,
- * SilcBool send_events);
+ * SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule,
+ * SilcUInt32 fd,
+ * SilcTaskEvent mask,
+ * SilcBool send_events);
*
* DESCRIPTION
*
* after the event occurs in reality. In normal cases the `send_events'
* is set to FALSE.
*
+ * Returns FALSE if the operation could not performed and TRUE if it
+ * was a success.
+ *
***/
-void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
- SilcTaskEvent mask, SilcBool send_events);
+SilcBool silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd,
+ SilcTaskEvent mask, SilcBool send_events);
/****f* silcutil/SilcScheduleAPI/silc_schedule_get_fd_events
*
SilcUInt32 data_len);
SilcBool silc_socket_stream_close(SilcStream stream);
void silc_socket_stream_destroy(SilcStream stream);
-void silc_socket_stream_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context);
+SilcBool silc_socket_stream_notifier(SilcStream stream,
+ SilcSchedule schedule,
+ SilcStreamNotifier callback,
+ void *context);
SilcSchedule silc_socket_stream_get_schedule(SilcStream stream);
/* Internal async host lookup context. */
return NULL;
}
- SILC_LOG_DEBUG(("Creating TCP socket stream %p", stream));
+ SILC_LOG_DEBUG(("Creating TCP socket stream %p, sock %lu", stream, sock));
stream->ops = &silc_socket_stream_ops;
stream->sock = sock;
h->ops->destroy(stream);
}
-void silc_stream_set_notifier(SilcStream stream, SilcSchedule schedule,
- SilcStreamNotifier notifier, void *context)
+SilcBool silc_stream_set_notifier(SilcStream stream, SilcSchedule schedule,
+ SilcStreamNotifier notifier, void *context)
{
SilcStreamHeader h = stream;
- h->ops->notifier(stream, schedule, notifier, context);
+ return h->ops->notifier(stream, schedule, notifier, context);
}
SilcSchedule silc_stream_get_schedule(SilcStream stream)
/* This is called to set a notifier callback to the stream and schedule
the stream. Stream should not be scheduled before calling this
function. If stream does not need scheduler then the scheduler can
- be ignored. This is called when silc_stream_set_notifier was called. */
- void (*notifier)(SilcStream stream, SilcSchedule schedule,
- SilcStreamNotifier callback, void *context);
+ be ignored. This is called when silc_stream_set_notifier was called.
+ Returns FALSE if the stream could not be scheduled. */
+ SilcBool (*notifier)(SilcStream stream, SilcSchedule schedule,
+ SilcStreamNotifier callback, void *context);
/* This is called to return the associated scheduler, if set. This is
called when silc_stream_get_schedule was called. */
* Closes the stream indicated by `stream'. No data can be read or written
* to the stream after calling this function. Return TRUE if the stream
* could be closed. If action is taken on closed stream the notifier
- * callback will be called with an error status.
+ * callback may be called with an error status.
*
***/
SilcBool silc_stream_close(SilcStream stream);
*
* SYNOPSIS
*
- * void silc_stream_set_notifier(SilcStream stream,
- * SilcSchedule schedule,
- * SilcStreamNotifier notifier,
- * void *context);
+ * SilcBool silc_stream_set_notifier(SilcStream stream,
+ * SilcSchedule schedule,
+ * SilcStreamNotifier notifier,
+ * void *context);
*
* DESCRIPTION
*
* Set a notifier callback for the stream indicated by `stream' to be called
* when some action takes place on the stream. This effectively means
* scheduling the stream for various actions, that then eventually will
- * be delivered to caller in the `notifier' callback. It is called for
+ * be delivered to caller in the `notifier' callback. It is called for
* example when data is available for reading or writing, or if an error
* occurs. This can be called at any time for valid stream.
+ *
* If `notifier' is set to NULL no callback will be called for the stream,
* and the stream is not scheduled anymore.
*
+ * This function returns FALSE if the `schedule' was provided and the
+ * stream could not be scheduled. The actual API for `stream' may provide
+ * access to the actual error information. Returns TRUE on success.
+ *
***/
-void silc_stream_set_notifier(SilcStream stream, SilcSchedule schedule,
- SilcStreamNotifier notifier, void *context);
+SilcBool silc_stream_set_notifier(SilcStream stream, SilcSchedule schedule,
+ SilcStreamNotifier notifier, void *context);
/****f* silcutil/SilcStreamAPI/silc_stream_get_schedule
*
/* Sets stream notification callback for the stream */
-void silc_socket_stream_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context)
+SilcBool silc_socket_stream_notifier(SilcStream stream,
+ SilcSchedule schedule,
+ SilcStreamNotifier callback,
+ void *context)
{
SilcSocketStream socket_stream = (SilcSocketStream)stream;
SilcSymbianSocket *s = (SilcSymbianSocket *)socket_stream->sock;
socket_stream->notifier = callback;
socket_stream->notifier_context = context;
socket_stream->schedule = schedule;
+
+ return TRUE;
}
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 Pekka Riikonen
+ Copyright (C) 1997 - 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
if (conn->aborted) {
/** Aborted */
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/* Do host lookup */
/** Network unreachable */
conn->status = SILC_NET_HOST_UNREACHABLE;
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/* Set sockaddr for this connection */
if (!silc_net_set_sockaddr(&desthost, conn->ip_addr, conn->port)) {
/** Sockaddr failed */
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/* Create the connection socket */
/** Cannot create socket */
SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/* Bind to the local address if provided */
/** Cannot connect to remote host */
SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
}
silc_schedule_set_listen_fd(silc_fsm_get_schedule(fsm), sock,
SILC_TASK_WRITE, FALSE);
SILC_FSM_EVENT_WAIT(&conn->event);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
static void silc_net_connect_wait_stream(SilcSocketStreamStatus status,
if (conn->aborted) {
/** Aborted */
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
ret = silc_net_get_socket_opt(conn->sock, SOL_SOCKET, SO_ERROR,
conn->retry--;
silc_net_close_connection(conn->sock);
silc_fsm_next(fsm, silc_net_connect_st_start);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
#if defined(ECONNREFUSED)
/** Connecting failed */
SILC_LOG_DEBUG(("Connecting failed"));
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/** Connection created */
if (conn->aborted) {
/** Aborted */
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
if (conn->stream_status != SILC_SOCKET_OK) {
else
conn->status = SILC_NET_ERROR;
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/* Set stream information */
conn->ip_addr, conn->ip_addr, conn->port);
/** Stream created successfully */
- SILC_LOG_DEBUG(("Connected successfully"));
+ SILC_LOG_DEBUG(("Connected successfully, sock %d", conn->sock));
conn->status = SILC_NET_OK;
silc_fsm_next(fsm, silc_net_connect_st_finish);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
SILC_FSM_STATE(silc_net_connect_st_finish)
silc_async_free(conn->sop);
}
- SILC_FSM_FINISH;
+ return SILC_FSM_FINISH;
}
static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
void silc_net_close_connection(int sock)
{
+ SILC_LOG_DEBUG(("Closing sock %d", sock));
close(sock);
}
struct epoll_event event;
if (!internal)
- return FALSE;
+ return TRUE;
+
+ SILC_LOG_DEBUG(("Scheduling fd %lu, mask %x", task->fd, event_mask));
event.events = 0;
- if (task->events & SILC_TASK_READ)
+ if (event_mask & SILC_TASK_READ)
event.events |= (EPOLLIN | EPOLLPRI);
- if (task->events & SILC_TASK_WRITE)
+ if (event_mask & SILC_TASK_WRITE)
event.events |= EPOLLOUT;
/* Zero mask unschedules task */
if (silc_unlikely(!event.events)) {
- epoll_ctl(internal->epfd, EPOLL_CTL_DEL, task->fd, &event);
+ if (epoll_ctl(internal->epfd, EPOLL_CTL_DEL, task->fd, &event)) {
+ SILC_LOG_DEBUG(("epoll_ctl (DEL): %s", strerror(errno)));
+ return FALSE;
+ }
return TRUE;
}
/* Schedule the task */
if (silc_unlikely(!task->scheduled)) {
event.data.ptr = task;
- epoll_ctl(internal->epfd, EPOLL_CTL_ADD, task->fd, &event);
+ if (epoll_ctl(internal->epfd, EPOLL_CTL_ADD, task->fd, &event)) {
+ SILC_LOG_DEBUG(("epoll_ctl (ADD): %s", strerror(errno)));
+ return FALSE;
+ }
task->scheduled = TRUE;
return TRUE;
}
/* Schedule for specific mask */
event.data.ptr = task;
- epoll_ctl(internal->epfd, EPOLL_CTL_MOD, task->fd, &event);
+ if (epoll_ctl(internal->epfd, EPOLL_CTL_MOD, task->fd, &event)) {
+ SILC_LOG_DEBUG(("epoll_ctl (MOD): %s", strerror(errno)));
+ return FALSE;
+ }
#endif /* HAVE_EPOLL_WAIT */
return TRUE;
}
SilcSocketStream socket_stream = stream;
silc_schedule_unset_listen_fd(socket_stream->schedule, socket_stream->sock);
+ silc_schedule_task_del_by_fd(socket_stream->schedule, socket_stream->sock);
silc_net_close_connection(socket_stream->sock);
return TRUE;
/* Sets stream notification callback for the stream */
-void silc_socket_stream_notifier(SilcStream stream,
- SilcSchedule schedule,
- SilcStreamNotifier callback,
- void *context)
+SilcBool silc_socket_stream_notifier(SilcStream stream,
+ SilcSchedule schedule,
+ SilcStreamNotifier callback,
+ void *context)
{
SilcSocketStream socket_stream = stream;
if (socket_stream->notifier) {
/* Add the socket to scheduler. Safe to call if already added. */
- silc_schedule_task_add_fd(socket_stream->schedule, socket_stream->sock,
- silc_socket_stream_io, socket_stream);
+ if (!silc_schedule_task_add_fd(socket_stream->schedule,
+ socket_stream->sock,
+ silc_socket_stream_io, socket_stream))
+ return FALSE;
/* Initially set socket for reading */
- silc_schedule_set_listen_fd(socket_stream->schedule, socket_stream->sock,
- SILC_TASK_READ, FALSE);
- silc_schedule_wakeup(socket_stream->schedule);
+ if (!silc_schedule_set_listen_fd(socket_stream->schedule,
+ socket_stream->sock,
+ SILC_TASK_READ, FALSE))
+ return FALSE;
} else {
/* Unschedule the socket */
silc_schedule_unset_listen_fd(socket_stream->schedule,
socket_stream->sock);
silc_schedule_task_del_by_fd(socket_stream->schedule,
socket_stream->sock);
- silc_schedule_wakeup(socket_stream->schedule);
}
+
+ silc_schedule_wakeup(socket_stream->schedule);
+ return TRUE;
}