Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2005 Pekka Riikonen
+ Copyright (C) 2005 - 2008 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
/************************** Types and definitions ***************************/
-#define SILC_IS_SOCKET_STREAM(s) (s->ops == &silc_socket_stream_ops)
-
-const SilcStreamOps silc_socket_stream_ops;
-
-/* Platform specific functions */
+/* Stream operation functions (platform specific) */
int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
SilcUInt32 buf_len);
int silc_socket_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);
+int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
+ SilcUInt32 buf_len);
+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);
+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. */
typedef struct {
/************************ 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 (!stream->notifier)
- return;
-
- switch (type) {
- case SILC_TASK_WRITE:
- stream->notifier(stream, SILC_STREAM_CAN_WRITE, stream->notifier_context);
- break;
-
- case SILC_TASK_READ:
- stream->notifier(stream, SILC_STREAM_CAN_READ, stream->notifier_context);
- break;
-
- default:
- break;
- }
-}
-
/* Finishing timeout callback that will actually call the user specified
host lookup callback. This is executed back in the calling thread and
not in the lookup thread. */
if (lookup->aborted) {
SILC_LOG_DEBUG(("Socket stream creation was aborted"));
- silc_net_close_connection(stream->sock);
- silc_free(stream->ip);
- silc_free(stream->hostname);
- silc_free(stream);
+ stream->schedule = NULL;
+ silc_socket_stream_destroy(stream);
silc_free(lookup);
return;
}
if (lookup->status != SILC_SOCKET_OK) {
- SILC_LOG_DEBUG(("Socket stream failed"));
- silc_net_close_connection(stream->sock);
- silc_free(stream->ip);
- silc_free(stream->hostname);
- silc_free(stream);
+ SILC_LOG_DEBUG(("Socket stream lookup failed"));
+ stream->schedule = NULL;
+ silc_socket_stream_destroy(stream);
stream = lookup->stream = NULL;
}
out:
silc_schedule_task_add_timeout(schedule, silc_socket_host_lookup_finish,
- lookup, 0, 1);
+ lookup, 0, 0);
silc_schedule_wakeup(schedule);
return NULL;
}
/******************************* Public API *********************************/
-/* Creates socket stream */
+/* Creates TCP socket stream */
SilcAsyncOperation
-silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn,
- SilcSchedule schedule,
- SilcSocketStreamCallback callback,
- void *context)
+silc_socket_tcp_stream_create(SilcSocket sock, SilcBool lookup,
+ SilcBool require_fqdn,
+ SilcSchedule schedule,
+ SilcSocketStreamCallback callback,
+ void *context)
{
SilcSocketStream stream;
SilcSocketHostLookup l;
+ if (!sock || !schedule) {
+ SILC_LOG_ERROR(("Missing arguments to silc_socket_tcp_stream_create"));
+ if (callback)
+ callback(SILC_SOCKET_ERROR, NULL, context);
+ return NULL;
+ }
+
stream = silc_calloc(1, sizeof(*stream));
if (!stream) {
if (callback)
return NULL;
}
- SILC_LOG_DEBUG(("Creating new 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;
stream->schedule = schedule;
+ stream->connected = TRUE;
l = silc_calloc(1, sizeof(*l));
if (!l) {
}
}
+/* Creates UDP socket stream */
+
+SilcStream silc_socket_udp_stream_create(SilcSocket sock, SilcBool ipv6,
+ SilcBool connected,
+ SilcSchedule schedule)
+{
+ SilcSocketStream stream;
+
+ stream = silc_calloc(1, sizeof(*stream));
+ if (!stream)
+ return NULL;
+
+ SILC_LOG_DEBUG(("Creating UDP socket stream %p", stream));
+
+ stream->ops = &silc_socket_udp_stream_ops;
+ stream->sock = sock;
+ stream->schedule = schedule;
+ stream->ipv6 = ipv6;
+ stream->connected = connected;
+
+ return (SilcStream)stream;
+}
+
+/* Returns TRUE if the stream is UDP stream */
+
+SilcBool silc_socket_stream_is_udp(SilcStream stream, SilcBool *connected)
+{
+ SilcSocketStream socket_stream = stream;
+
+ if (!SILC_IS_SOCKET_STREAM_UDP(socket_stream))
+ return FALSE;
+
+ if (connected)
+ *connected = socket_stream->connected;
+
+ return TRUE;
+}
+
/* Returns socket stream information */
SilcBool silc_socket_stream_get_info(SilcStream stream,
- int *sock, const char **hostname,
+ SilcSocket *sock, const char **hostname,
const char **ip, SilcUInt16 *port)
{
SilcSocketStream socket_stream = stream;
- if (!SILC_IS_SOCKET_STREAM(socket_stream))
+ if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
+ !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
return FALSE;
if (sock)
*sock = socket_stream->sock;
- if (hostname)
- *hostname = socket_stream->hostname;
- if (ip)
- *ip = socket_stream->ip;
- if (port)
+ if (port) {
+ if (!socket_stream->port)
+ return FALSE;
*port = socket_stream->port;
+ }
+ if (ip) {
+ if (!socket_stream->ip)
+ return FALSE;
+ *ip = socket_stream->ip;
+ }
+ if (hostname) {
+ if (!socket_stream->hostname)
+ return FALSE;
+ *hostname = socket_stream->hostname;
+ }
return TRUE;
}
{
SilcSocketStream socket_stream = stream;
- if (!SILC_IS_SOCKET_STREAM(socket_stream))
+ if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
+ !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
return FALSE;
if (hostname) {
socket_stream->ip = strdup(ip);
if (!socket_stream->ip)
return FALSE;
+ if (!socket_stream->hostname) {
+ socket_stream->hostname = strdup(ip);
+ if (!socket_stream->hostname)
+ return FALSE;
+ }
}
if (port)
socket_stream->port = port;
{
SilcSocketStream socket_stream = stream;
- if (!SILC_IS_SOCKET_STREAM(socket_stream))
+ if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
+ !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
return 0;
return socket_stream->sock_error;
{
SilcSocketStream socket_stream = stream;
- if (!SILC_IS_SOCKET_STREAM(socket_stream))
+ if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
+ !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
return FALSE;
SILC_LOG_DEBUG(("Setting QoS for socket stream"));
!limit_sec && !limit_usec) {
silc_schedule_task_del_by_context(socket_stream->schedule,
socket_stream->qos);
+ silc_free(socket_stream->qos->buffer);
silc_free(socket_stream->qos);
socket_stream->qos = NULL;
return TRUE;
socket_stream->qos->cur_rate = 0;
socket_stream->qos->sock = socket_stream;
- socket_stream->qos->buffer = silc_malloc(read_limit_bytes);
+ socket_stream->qos->buffer = silc_realloc(socket_stream->qos->buffer,
+ read_limit_bytes);
if (!socket_stream->qos->buffer)
return FALSE;
return TRUE;
}
-/* Closes socket */
-
-SilcBool silc_socket_stream_close(SilcStream stream)
-{
- SilcSocketStream socket_stream = stream;
-
- if (!SILC_IS_SOCKET_STREAM(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))
- return;
-
- silc_socket_stream_close(socket_stream);
- silc_free(socket_stream->ip);
- silc_free(socket_stream->hostname);
- 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);
- }
-
- 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))
- 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);
- } 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);
- }
-}
-
/* Return associated scheduler */
SilcSchedule silc_socket_stream_get_schedule(SilcStream stream)
{
SilcSocketStream socket_stream = stream;
- if (!SILC_IS_SOCKET_STREAM(socket_stream))
+ if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
+ !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
return NULL;
return socket_stream->schedule;
silc_socket_stream_notifier,
silc_socket_stream_get_schedule,
};
+const SilcStreamOps silc_socket_udp_stream_ops =
+{
+ silc_socket_udp_stream_read,
+ silc_socket_udp_stream_write,
+ silc_socket_stream_close,
+ silc_socket_stream_destroy,
+ silc_socket_stream_notifier,
+ silc_socket_stream_get_schedule,
+};