#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. */
}
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;
}
SilcUInt32 data_len)
{
SilcSocketStream sock = stream;
- int ret;
- SILC_LOG_DEBUG(("Writing data to UDP socket %d", sock->sock));
+ /* 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);
- 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;
- }
-
- 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
return TRUE;
}
#endif /* 0 */
+
+/* Closes socket */
+
+SilcBool silc_socket_stream_close(SilcStream stream)
+{
+ SilcSocketStream socket_stream = stream;
+
+ 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;
+
+ 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;
+
+ 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);
+ }
+}