5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2005 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 /************************** Types and definitions ***************************/
24 /* Stream operation functions (platform specific) */
25 int silc_socket_stream_read(SilcStream stream, unsigned char *buf,
27 int silc_socket_stream_write(SilcStream stream, const unsigned char *data,
29 SilcBool silc_socket_stream_close(SilcStream stream);
30 void silc_socket_stream_destroy(SilcStream stream);
31 int silc_socket_udp_stream_read(SilcStream stream, unsigned char *buf,
33 int silc_socket_udp_stream_write(SilcStream stream, const unsigned char *data,
35 SilcBool silc_socket_stream_close(SilcStream stream);
36 void silc_socket_stream_destroy(SilcStream stream);
37 SilcBool silc_socket_stream_notifier(SilcStream stream,
38 SilcSchedule schedule,
39 SilcStreamNotifier callback,
41 SilcSchedule silc_socket_stream_get_schedule(SilcStream stream);
43 /* Internal async host lookup context. */
45 SilcSocketStream stream;
46 SilcSocketStreamStatus status;
47 SilcSocketStreamCallback callback;
48 SilcAsyncOperation op;
50 unsigned int require_fqdn : 1;
51 unsigned int aborted : 1;
52 } *SilcSocketHostLookup;
55 /************************ Static utility functions **************************/
57 /* Finishing timeout callback that will actually call the user specified
58 host lookup callback. This is executed back in the calling thread and
59 not in the lookup thread. */
61 SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
63 SilcSocketHostLookup lookup = context;
64 SilcSocketStream stream = lookup->stream;
66 if (lookup->aborted) {
67 SILC_LOG_DEBUG(("Socket stream creation was aborted"));
68 stream->schedule = NULL;
69 silc_socket_stream_destroy(stream);
74 if (lookup->status != SILC_SOCKET_OK) {
75 SILC_LOG_DEBUG(("Socket stream lookup failed"));
76 stream->schedule = NULL;
77 silc_socket_stream_destroy(stream);
78 stream = lookup->stream = NULL;
81 /* Return the created socket stream to the caller */
83 lookup->callback(lookup->status, stream, lookup->context);
86 silc_async_free(lookup->op);
90 /* The thread function that performs the actual lookup. */
92 static void *silc_socket_host_lookup_start(void *context)
94 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
95 SilcSocketStream stream = lookup->stream;
96 SilcSchedule schedule = stream->schedule;
98 stream->port = silc_net_get_remote_port(stream->sock);
100 silc_net_check_host_by_sock(stream->sock, &stream->hostname, &stream->ip);
102 lookup->status = SILC_SOCKET_UNKNOWN_IP;
106 if (!stream->hostname && lookup->require_fqdn) {
107 lookup->status = SILC_SOCKET_UNKNOWN_HOST;
111 if (!stream->hostname) {
112 stream->hostname = strdup(stream->ip);
113 if (!stream->hostname) {
114 lookup->status = SILC_SOCKET_NO_MEMORY;
119 lookup->status = SILC_SOCKET_OK;
122 silc_schedule_task_add_timeout(schedule, silc_socket_host_lookup_finish,
124 silc_schedule_wakeup(schedule);
128 /* Abort callback for stream creation. */
130 static void silc_socket_host_lookup_abort(SilcAsyncOperation op,
133 SilcSocketHostLookup lookup = context;
135 /* The host lookup is done in thread. We'll let it finish in its own
136 good time and handle the abortion after it finishes. */
137 lookup->aborted = TRUE;
141 /******************************* Public API *********************************/
143 /* Creates TCP socket stream */
146 silc_socket_tcp_stream_create(SilcSocket sock, SilcBool lookup,
147 SilcBool require_fqdn,
148 SilcSchedule schedule,
149 SilcSocketStreamCallback callback,
152 SilcSocketStream stream;
153 SilcSocketHostLookup l;
155 if (!sock || !schedule) {
156 SILC_LOG_ERROR(("Missing arguments to silc_socket_tcp_stream_create"));
158 callback(SILC_SOCKET_ERROR, NULL, context);
162 stream = silc_calloc(1, sizeof(*stream));
165 callback(SILC_SOCKET_NO_MEMORY, NULL, context);
169 SILC_LOG_DEBUG(("Creating TCP socket stream %p, sock %lu", stream, sock));
171 stream->ops = &silc_socket_stream_ops;
173 stream->schedule = schedule;
175 l = silc_calloc(1, sizeof(*l));
179 callback(SILC_SOCKET_NO_MEMORY, NULL, context);
184 l->callback = callback;
185 l->context = context;
186 l->require_fqdn = require_fqdn;
189 /* Start asynchronous IP, hostname and port lookup process */
190 l->op = silc_async_alloc(silc_socket_host_lookup_abort, NULL, l);
195 callback(SILC_SOCKET_ERROR, NULL, context);
199 /* Lookup in thread */
200 SILC_LOG_DEBUG(("Starting async host lookup"));
201 silc_thread_create(silc_socket_host_lookup_start, l, FALSE);
205 l->status = SILC_SOCKET_OK;
206 silc_socket_host_lookup_finish(schedule,
207 silc_schedule_get_context(schedule),
213 /* Creates UDP socket stream */
215 SilcStream silc_socket_udp_stream_create(SilcSocket sock, SilcBool ipv6,
217 SilcSchedule schedule)
219 SilcSocketStream stream;
221 stream = silc_calloc(1, sizeof(*stream));
225 SILC_LOG_DEBUG(("Creating UDP socket stream %p", stream));
227 stream->ops = &silc_socket_udp_stream_ops;
229 stream->schedule = schedule;
231 stream->connected = connected;
233 return (SilcStream)stream;
236 /* Returns TRUE if the stream is UDP stream */
238 SilcBool silc_socket_stream_is_udp(SilcStream stream, SilcBool *connected)
240 SilcSocketStream socket_stream = stream;
242 if (!SILC_IS_SOCKET_STREAM_UDP(socket_stream))
246 *connected = socket_stream->connected;
251 /* Returns socket stream information */
253 SilcBool silc_socket_stream_get_info(SilcStream stream,
254 SilcSocket *sock, const char **hostname,
255 const char **ip, SilcUInt16 *port)
257 SilcSocketStream socket_stream = stream;
259 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
260 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
264 *sock = socket_stream->sock;
266 if (!socket_stream->port)
268 *port = socket_stream->port;
271 if (!socket_stream->ip)
273 *ip = socket_stream->ip;
276 if (!socket_stream->hostname)
278 *hostname = socket_stream->hostname;
284 /* Set socket information */
286 SilcBool silc_socket_stream_set_info(SilcStream stream,
287 const char *hostname,
288 const char *ip, SilcUInt16 port)
290 SilcSocketStream socket_stream = stream;
292 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
293 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
297 silc_free(socket_stream->hostname);
298 socket_stream->hostname = strdup(hostname);
299 if (!socket_stream->hostname)
303 silc_free(socket_stream->ip);
304 socket_stream->ip = strdup(ip);
305 if (!socket_stream->ip)
307 if (!socket_stream->hostname) {
308 socket_stream->hostname = strdup(ip);
309 if (!socket_stream->hostname)
314 socket_stream->port = port;
319 /* Return socket errno */
321 int silc_socket_stream_get_error(SilcStream stream)
323 SilcSocketStream socket_stream = stream;
325 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
326 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
329 return socket_stream->sock_error;
332 /* Set QoS for socket stream */
334 SilcBool silc_socket_stream_set_qos(SilcStream stream,
335 SilcUInt32 read_rate,
336 SilcUInt32 read_limit_bytes,
337 SilcUInt32 limit_sec,
338 SilcUInt32 limit_usec)
340 SilcSocketStream socket_stream = stream;
342 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
343 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
346 SILC_LOG_DEBUG(("Setting QoS for socket stream"));
348 if (socket_stream->qos && !read_rate && !read_limit_bytes &&
349 !limit_sec && !limit_usec) {
350 silc_schedule_task_del_by_context(socket_stream->schedule,
352 silc_free(socket_stream->qos);
353 socket_stream->qos = NULL;
357 if (!socket_stream->qos) {
358 socket_stream->qos = silc_calloc(1, sizeof(*socket_stream->qos));
359 if (!socket_stream->qos)
363 socket_stream->qos->read_rate = read_rate;
364 socket_stream->qos->read_limit_bytes = read_limit_bytes;
365 socket_stream->qos->limit_sec = limit_sec;
366 socket_stream->qos->limit_usec = limit_usec;
367 memset(&socket_stream->qos->next_limit, 0,
368 sizeof(socket_stream->qos->next_limit));
369 socket_stream->qos->cur_rate = 0;
370 socket_stream->qos->sock = socket_stream;
372 socket_stream->qos->buffer = silc_malloc(read_limit_bytes);
373 if (!socket_stream->qos->buffer)
379 /* Return associated scheduler */
381 SilcSchedule silc_socket_stream_get_schedule(SilcStream stream)
383 SilcSocketStream socket_stream = stream;
385 if (!SILC_IS_SOCKET_STREAM(socket_stream) &&
386 !SILC_IS_SOCKET_STREAM_UDP(socket_stream))
389 return socket_stream->schedule;
392 /* SILC Socket Stream ops. Functions are implemented under the
393 platform specific subdirectories. */
394 const SilcStreamOps silc_socket_stream_ops =
396 silc_socket_stream_read,
397 silc_socket_stream_write,
398 silc_socket_stream_close,
399 silc_socket_stream_destroy,
400 silc_socket_stream_notifier,
401 silc_socket_stream_get_schedule,
403 const SilcStreamOps silc_socket_udp_stream_ops =
405 silc_socket_udp_stream_read,
406 silc_socket_udp_stream_write,
407 silc_socket_stream_close,
408 silc_socket_stream_destroy,
409 silc_socket_stream_notifier,
410 silc_socket_stream_get_schedule,