X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Funix%2Fsilcunixsocketstream.c;h=1b9d66295036a22721ed963d1e44d262aed27bd4;hb=9905799a86c606304fd7df2cd401de1740a272a1;hp=10e6e8418fd0a963d37bdf7ae8ee1974886cf77a;hpb=c27a4ecc3e616e8a5ee09b8ca888ed6ff3e501f7;p=silc.git diff --git a/lib/silcutil/unix/silcunixsocketstream.c b/lib/silcutil/unix/silcunixsocketstream.c index 10e6e841..1b9d6629 100644 --- a/lib/silcutil/unix/silcunixsocketstream.c +++ b/lib/silcutil/unix/silcunixsocketstream.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2005 Pekka Riikonen + Copyright (C) 1997 - 2006 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 @@ -18,7 +18,34 @@ */ /* $Id$ */ -#include "silcincludes.h" +#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,17 +195,42 @@ 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; } +/* Receive UDP packet. QoS is not supported. */ + +int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf, + SilcUInt32 buf_len) +{ + return silc_net_udp_receive(stream, NULL, 0, NULL, buf, buf_len); +} + +/* Send UDP packet. This always succeeds. */ + +int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data, + SilcUInt32 data_len) +{ + SilcSocketStream sock = stream; + + /* 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); + + /* In connected state use normal writing to socket. */ + return silc_socket_stream_write(stream, data, data_len); +} + #if 0 /* Returns human readable socket error message */ SilcBool silc_socket_get_error(SilcStream sock, char *error, - SilcUInt32 error_len) + SilcUInt32 error_len) { char *err; @@ -194,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); + } +}