X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcsocketstream.c;h=e11fff73a5a5b29fdd1922b6d1b2b60476fedc97;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=e67678497ad964d66ece1505023e1870b78ef2a8;hpb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;p=silc.git diff --git a/lib/silcutil/silcsocketstream.c b/lib/silcutil/silcsocketstream.c index e6767849..e11fff73 100644 --- a/lib/silcutil/silcsocketstream.c +++ b/lib/silcutil/silcsocketstream.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2005 Pekka Riikonen + Copyright (C) 2005 - 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 @@ -21,22 +21,29 @@ /************************** 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 { SilcSocketStream stream; - SilcSocketStreamStatus status; + SilcResult status; SilcSocketStreamCallback callback; SilcAsyncOperation op; void *context; @@ -47,30 +54,6 @@ 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. */ @@ -82,20 +65,16 @@ SILC_TASK_CALLBACK(silc_socket_host_lookup_finish) 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); + if (lookup->status != SILC_OK) { + SILC_LOG_DEBUG(("Socket stream lookup failed")); + stream->schedule = NULL; + silc_socket_stream_destroy(stream); stream = lookup->stream = NULL; } @@ -120,28 +99,28 @@ static void *silc_socket_host_lookup_start(void *context) silc_net_check_host_by_sock(stream->sock, &stream->hostname, &stream->ip); if (!stream->ip) { - lookup->status = SILC_SOCKET_UNKNOWN_IP; + lookup->status = SILC_ERR_UNKNOWN_IP; goto out; } if (!stream->hostname && lookup->require_fqdn) { - lookup->status = SILC_SOCKET_UNKNOWN_HOST; + lookup->status = SILC_ERR_UNKNOWN_HOST; goto out; } if (!stream->hostname) { - stream->hostname = strdup(stream->ip); + stream->hostname = silc_strdup(stream->ip); if (!stream->hostname) { - lookup->status = SILC_SOCKET_NO_MEMORY; + lookup->status = SILC_ERR_OUT_OF_MEMORY; goto out; } } - lookup->status = SILC_SOCKET_OK; + lookup->status = SILC_OK; out: silc_schedule_task_add_timeout(schedule, silc_socket_host_lookup_finish, - lookup, 0, 1); + lookup, 0, 0); silc_schedule_wakeup(schedule); return NULL; } @@ -161,35 +140,54 @@ static void silc_socket_host_lookup_abort(SilcAsyncOperation op, /******************************* 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 (!schedule) { + schedule = silc_schedule_get_global(); + if (!schedule) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + if (callback) + callback(silc_errno, NULL, context); + return NULL; + } + } + + if (!sock) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + if (callback) + callback(silc_errno, NULL, context); + return NULL; + } + stream = silc_calloc(1, sizeof(*stream)); if (!stream) { if (callback) - callback(SILC_SOCKET_NO_MEMORY, NULL, context); + callback(silc_errno, NULL, context); 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) { silc_free(stream); if (callback) - callback(SILC_SOCKET_NO_MEMORY, NULL, context); + callback(silc_errno, NULL, context); return NULL; } @@ -205,7 +203,7 @@ silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn, silc_free(stream); silc_free(l); if (callback) - callback(SILC_SOCKET_ERROR, NULL, context); + callback(silc_errno, NULL, context); return NULL; } @@ -215,7 +213,7 @@ silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn, return l->op; } else { /* No lookup */ - l->status = SILC_SOCKET_OK; + l->status = SILC_OK; silc_socket_host_lookup_finish(schedule, silc_schedule_get_context(schedule), 0, 0, l); @@ -223,25 +221,81 @@ silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn, } } +/* Creates UDP socket stream */ + +SilcStream silc_socket_udp_stream_create(SilcSocket sock, SilcBool ipv6, + SilcBool connected, + SilcSchedule schedule) +{ + SilcSocketStream stream; + + if (!schedule) { + schedule = silc_schedule_get_global(); + if (!schedule) { + silc_set_errno(SILC_ERR_INVALID_ARGUMENT); + return NULL; + } + } + + 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; } @@ -254,20 +308,26 @@ SilcBool silc_socket_stream_set_info(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 FALSE; if (hostname) { silc_free(socket_stream->hostname); - socket_stream->hostname = strdup(hostname); + socket_stream->hostname = silc_strdup(hostname); if (!socket_stream->hostname) return FALSE; } if (ip) { silc_free(socket_stream->ip); - socket_stream->ip = strdup(ip); + socket_stream->ip = silc_strdup(ip); if (!socket_stream->ip) return FALSE; + if (!socket_stream->hostname) { + socket_stream->hostname = silc_strdup(ip); + if (!socket_stream->hostname) + return FALSE; + } } if (port) socket_stream->port = port; @@ -275,18 +335,6 @@ SilcBool silc_socket_stream_set_info(SilcStream stream, return TRUE; } -/* Return socket errno */ - -int silc_socket_stream_get_error(SilcStream stream) -{ - SilcSocketStream socket_stream = stream; - - if (!SILC_IS_SOCKET_STREAM(socket_stream)) - return 0; - - return socket_stream->sock_error; -} - /* Set QoS for socket stream */ SilcBool silc_socket_stream_set_qos(SilcStream stream, @@ -297,7 +345,8 @@ SilcBool silc_socket_stream_set_qos(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 FALSE; SILC_LOG_DEBUG(("Setting QoS for socket stream")); @@ -333,91 +382,14 @@ SilcBool silc_socket_stream_set_qos(SilcStream stream, 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; @@ -434,3 +406,12 @@ const SilcStreamOps silc_socket_stream_ops = 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, +};