X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Funix%2Fsilcunixsocketstream.c;h=1b9d66295036a22721ed963d1e44d262aed27bd4;hb=9905799a86c606304fd7df2cd401de1740a272a1;hp=1eded3d36b351e8a76a0c49f2fc9bd7363ad8b93;hpb=c14dc73816933bb82e63a2ffbc90eaca9c9895d3;p=silc.git diff --git a/lib/silcutil/unix/silcunixsocketstream.c b/lib/silcutil/unix/silcunixsocketstream.c index 1eded3d3..1b9d6629 100644 --- a/lib/silcutil/unix/silcunixsocketstream.c +++ b/lib/silcutil/unix/silcunixsocketstream.c @@ -20,6 +20,33 @@ #include "silc.h" +/************************ Static utility functions **************************/ + +/* The IO process callback that calls the notifier callback to upper layer. */ + +SILC_TASK_CALLBACK(silc_socket_stream_io) +{ + SilcSocketStream stream = context; + + if (silc_unlikely(!stream->notifier)) + return; + + switch (type) { + 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; + } +} + +/**************************** Stream Operations *****************************/ + /* QoS read handler, this will call the read and write events to indicate that data is available again after a timeout. */ @@ -168,8 +195,10 @@ int silc_socket_stream_write(SilcStream stream, const unsigned char *data, } SILC_LOG_DEBUG(("Wrote data %d bytes", ret)); - silc_schedule_set_listen_fd(sock->schedule, sock->sock, - SILC_TASK_READ, FALSE); + if (silc_schedule_get_fd_events(sock->schedule, sock->sock) & + SILC_TASK_WRITE) + silc_schedule_set_listen_fd(sock->schedule, sock->sock, + SILC_TASK_READ, FALSE); return ret; } @@ -188,19 +217,13 @@ int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data, SilcUInt32 data_len) { SilcSocketStream sock = stream; - int ret; - SILC_LOG_DEBUG(("Writing data to UDP socket %d", sock->sock)); - - ret = send(sock->sock, data, data_len, 0); - if (ret < 0) { - /* Ignore error and return success */ - SILC_LOG_DEBUG(("Cannot write to UDP socket: %s", strerror(errno))); - return data_len; - } + /* In connectionless state check if remote IP and port is provided */ + if (!sock->connected && sock->ip && sock->port) + return silc_net_udp_send(stream, sock->ip, sock->port, data, data_len); - SILC_LOG_DEBUG(("Wrote data %d bytes", ret)); - return ret; + /* In connected state use normal writing to socket. */ + return silc_socket_stream_write(stream, data, data_len); } #if 0 @@ -223,3 +246,90 @@ SilcBool silc_socket_get_error(SilcStream sock, char *error, return TRUE; } #endif /* 0 */ + +/* Closes socket */ + +SilcBool silc_socket_stream_close(SilcStream stream) +{ + SilcSocketStream socket_stream = stream; + + if (!SILC_IS_SOCKET_STREAM(socket_stream) && + !SILC_IS_SOCKET_STREAM_UDP(socket_stream)) + return FALSE; + + silc_schedule_unset_listen_fd(socket_stream->schedule, socket_stream->sock); + silc_net_close_connection(socket_stream->sock); + + return TRUE; +} + +/* Destroys the stream */ + +void silc_socket_stream_destroy(SilcStream stream) +{ + SilcSocketStream socket_stream = stream; + + if (!SILC_IS_SOCKET_STREAM(socket_stream) && + !SILC_IS_SOCKET_STREAM_UDP(socket_stream)) + return; + + silc_socket_stream_close(socket_stream); + silc_free(socket_stream->ip); + silc_free(socket_stream->hostname); + if (socket_stream->schedule) + silc_schedule_task_del_by_fd(socket_stream->schedule, socket_stream->sock); + + if (socket_stream->qos) { + silc_schedule_task_del_by_context(socket_stream->schedule, + socket_stream->qos); + if (socket_stream->qos->buffer) { + memset(socket_stream->qos->buffer, 0, + socket_stream->qos->read_limit_bytes); + silc_free(socket_stream->qos->buffer); + } + silc_free(socket_stream->qos); + } + + if (socket_stream->schedule) + silc_schedule_wakeup(socket_stream->schedule); + + silc_free(socket_stream); +} + +/* Sets stream notification callback for the stream */ + +void silc_socket_stream_notifier(SilcStream stream, + SilcSchedule schedule, + SilcStreamNotifier callback, + void *context) +{ + SilcSocketStream socket_stream = stream; + + if (!SILC_IS_SOCKET_STREAM(socket_stream) && + !SILC_IS_SOCKET_STREAM_UDP(socket_stream)) + return; + + SILC_LOG_DEBUG(("Setting stream notifier callback")); + + socket_stream->notifier = callback; + socket_stream->notifier_context = context; + socket_stream->schedule = schedule; + + 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); + + /* 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); + } 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); + } +}