From: Pekka Riikonen Date: Tue, 23 Jan 2007 14:47:00 +0000 (+0000) Subject: silc_stream_set_notifier and silc_schedule_set_listen_fd now X-Git-Tag: silc.client.1.1.beta1~55 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=9781db929f51eec844277fbe28780faaea35e53f silc_stream_set_notifier and silc_schedule_set_listen_fd now returns error condition. Fixed FD task addition when FD task already exists. --- diff --git a/lib/silcutil/silcfdstream.c b/lib/silcutil/silcfdstream.c index cbd837aa..67ad3269 100644 --- a/lib/silcutil/silcfdstream.c +++ b/lib/silcutil/silcfdstream.c @@ -233,10 +233,12 @@ SilcBool silc_fd_stream_close(SilcStream stream) 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; @@ -246,20 +248,16 @@ SilcBool silc_fd_stream_close(SilcStream stream) 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; @@ -288,7 +286,11 @@ void silc_fd_stream_notifier(SilcStream 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 */ diff --git a/lib/silcutil/silcschedule.c b/lib/silcutil/silcschedule.c index aa648e39..5d1760cc 100644 --- a/lib/silcutil/silcschedule.c +++ b/lib/silcutil/silcschedule.c @@ -600,20 +600,30 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd, /* 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)); @@ -625,9 +635,17 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 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; @@ -689,8 +707,10 @@ void silc_schedule_task_del_by_fd(SilcSchedule schedule, SilcUInt32 fd) /* 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); @@ -793,20 +813,23 @@ void silc_schedule_task_del_by_all(SilcSchedule schedule, int fd, 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); @@ -814,9 +837,11 @@ void silc_schedule_set_listen_fd(SilcSchedule schedule, SilcUInt32 fd, } 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) diff --git a/lib/silcutil/silcschedule.h b/lib/silcutil/silcschedule.h index 4dc15c50..32557df9 100644 --- a/lib/silcutil/silcschedule.h +++ b/lib/silcutil/silcschedule.h @@ -375,6 +375,9 @@ void *silc_schedule_get_context(SilcSchedule schedule); * 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) @@ -530,9 +533,10 @@ void silc_schedule_task_del_by_all(SilcSchedule schedule, int 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 * @@ -550,9 +554,12 @@ void silc_schedule_task_del_by_all(SilcSchedule schedule, int fd, * 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 * diff --git a/lib/silcutil/silcsocketstream.c b/lib/silcutil/silcsocketstream.c index c3206447..a617f45c 100644 --- a/lib/silcutil/silcsocketstream.c +++ b/lib/silcutil/silcsocketstream.c @@ -34,10 +34,10 @@ int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data, 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. */ @@ -165,7 +165,7 @@ silc_socket_tcp_stream_create(SilcSocket sock, SilcBool lookup, 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; diff --git a/lib/silcutil/silcstream.c b/lib/silcutil/silcstream.c index 7b8b08af..af4789df 100644 --- a/lib/silcutil/silcstream.c +++ b/lib/silcutil/silcstream.c @@ -49,11 +49,11 @@ void silc_stream_destroy(SilcStream stream) 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) diff --git a/lib/silcutil/silcstream.h b/lib/silcutil/silcstream.h index efa161f1..4c8c0eb6 100644 --- a/lib/silcutil/silcstream.h +++ b/lib/silcutil/silcstream.h @@ -147,9 +147,10 @@ typedef struct { /* 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. */ @@ -208,7 +209,7 @@ int silc_stream_write(SilcStream stream, const unsigned char *data, * 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); @@ -234,25 +235,30 @@ void silc_stream_destroy(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 * diff --git a/lib/silcutil/symbian/silcsymbiansocketstream.cpp b/lib/silcutil/symbian/silcsymbiansocketstream.cpp index 3fcb7cec..7d791169 100644 --- a/lib/silcutil/symbian/silcsymbiansocketstream.cpp +++ b/lib/silcutil/symbian/silcsymbiansocketstream.cpp @@ -384,10 +384,10 @@ void silc_socket_stream_destroy(SilcStream stream) /* 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; @@ -400,4 +400,6 @@ void silc_socket_stream_notifier(SilcStream stream, socket_stream->notifier = callback; socket_stream->notifier_context = context; socket_stream->schedule = schedule; + + return TRUE; } diff --git a/lib/silcutil/unix/silcunixnet.c b/lib/silcutil/unix/silcunixnet.c index 1ce20381..f7ddb18d 100644 --- a/lib/silcutil/unix/silcunixnet.c +++ b/lib/silcutil/unix/silcunixnet.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - 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 @@ -489,7 +489,7 @@ SILC_FSM_STATE(silc_net_connect_st_start) if (conn->aborted) { /** Aborted */ silc_fsm_next(fsm, silc_net_connect_st_finish); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /* Do host lookup */ @@ -502,14 +502,14 @@ SILC_FSM_STATE(silc_net_connect_st_start) /** 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 */ @@ -525,7 +525,7 @@ SILC_FSM_STATE(silc_net_connect_st_start) /** 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 */ @@ -559,7 +559,7 @@ SILC_FSM_STATE(silc_net_connect_st_start) /** 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; } } @@ -581,7 +581,7 @@ SILC_FSM_STATE(silc_net_connect_st_start) 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, @@ -602,7 +602,7 @@ SILC_FSM_STATE(silc_net_connect_st_connected) 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, @@ -618,7 +618,7 @@ SILC_FSM_STATE(silc_net_connect_st_connected) 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) @@ -637,7 +637,7 @@ SILC_FSM_STATE(silc_net_connect_st_connected) /** 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 */ @@ -655,7 +655,7 @@ SILC_FSM_STATE(silc_net_connect_st_stream) 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) { @@ -667,7 +667,7 @@ SILC_FSM_STATE(silc_net_connect_st_stream) 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 */ @@ -676,10 +676,10 @@ SILC_FSM_STATE(silc_net_connect_st_stream) 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) @@ -695,7 +695,7 @@ 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) @@ -774,6 +774,7 @@ SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr, void silc_net_close_connection(int sock) { + SILC_LOG_DEBUG(("Closing sock %d", sock)); close(sock); } diff --git a/lib/silcutil/unix/silcunixschedule.c b/lib/silcutil/unix/silcunixschedule.c index 14fd31ef..df080730 100644 --- a/lib/silcutil/unix/silcunixschedule.c +++ b/lib/silcutil/unix/silcunixschedule.c @@ -267,31 +267,42 @@ SilcBool silc_schedule_internal_schedule_fd(SilcSchedule schedule, 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; } diff --git a/lib/silcutil/unix/silcunixsocketstream.c b/lib/silcutil/unix/silcunixsocketstream.c index 046c795c..a50f3e46 100644 --- a/lib/silcutil/unix/silcunixsocketstream.c +++ b/lib/silcutil/unix/silcunixsocketstream.c @@ -254,6 +254,7 @@ SilcBool silc_socket_stream_close(SilcStream stream) 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; @@ -290,10 +291,10 @@ void silc_socket_stream_destroy(SilcStream stream) /* 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; @@ -305,19 +306,24 @@ void silc_socket_stream_notifier(SilcStream 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; }