5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "silcincludes.h"
24 /* Heartbeat context */
25 struct SilcSocketConnectionHBStruct {
27 SilcSocketConnectionHBCb hb_callback;
31 SilcSocketConnection sock;
34 /* Internal async host lookup context. */
36 SilcSocketHostLookupCb callback;
39 SilcSocketConnection sock;
41 } *SilcSocketHostLookup;
43 /* Allocates a new socket connection object. The allocated object is
44 returned to the new_socket argument. */
46 void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
47 SilcSocketConnection *new_socket)
49 SILC_LOG_DEBUG(("Allocating new socket connection object"));
51 /* Set the pointers. Incoming and outgoing data buffers
52 are allocated by the application when they are first used. */
53 *new_socket = silc_calloc(1, sizeof(**new_socket));
54 (*new_socket)->sock = sock;
55 (*new_socket)->type = type;
56 (*new_socket)->user_data = user_data;
57 (*new_socket)->protocol = NULL;
58 (*new_socket)->flags = 0;
59 (*new_socket)->inbuf = NULL;
60 (*new_socket)->outbuf = NULL;
61 (*new_socket)->users++;
64 /* Free's the Socket connection object. */
66 void silc_socket_free(SilcSocketConnection sock)
69 SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users + 1,
71 if (sock->users < 1) {
72 silc_buffer_free(sock->inbuf);
73 silc_buffer_free(sock->outbuf);
75 silc_task_unregister(sock->hb->timeout_queue, sock->hb->hb_task);
76 silc_free(sock->hb->hb_context);
80 memset(sock, 'F', sizeof(*sock));
85 /* Increase the reference counter. */
87 SilcSocketConnection silc_socket_dup(SilcSocketConnection sock)
90 SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users - 1,
95 /* Internal timeout callback to perform heartbeat */
97 SILC_TASK_CALLBACK(silc_socket_heartbeat)
99 SilcSocketConnectionHB hb = (SilcSocketConnectionHB)context;
105 hb->hb_callback(hb->sock, hb->hb_context);
107 hb->hb_task = silc_task_register(hb->timeout_queue, hb->sock->sock,
108 silc_socket_heartbeat,
109 context, hb->heartbeat, 0,
114 /* Sets the heartbeat timeout and prepares the socket for performing
115 heartbeat in `heartbeat' intervals (seconds). The `hb_context' is
116 allocated by the application and will be sent as argument to the
117 `hb_callback' function that is called when the `heartbeat' timeout
118 expires. The callback `hb_context' won't be touched by the library
119 but will be freed automatically when calling silc_socket_free. The
120 `timeout_queue' is the application's scheduler timeout queue. */
122 void silc_socket_set_heartbeat(SilcSocketConnection sock,
125 SilcSocketConnectionHBCb hb_callback,
133 silc_task_unregister(sock->hb->timeout_queue, sock->hb->hb_task);
134 silc_free(sock->hb->hb_context);
138 sock->hb = silc_calloc(1, sizeof(*sock->hb));
139 sock->hb->heartbeat = heartbeat;
140 sock->hb->hb_context = hb_context;
141 sock->hb->hb_callback = hb_callback;
142 sock->hb->timeout_queue = timeout_queue;
143 sock->hb->sock = sock;
144 sock->hb->hb_task = silc_task_register(timeout_queue, sock->sock,
145 silc_socket_heartbeat,
146 (void *)sock->hb, heartbeat, 0,
151 /* Finishing timeout callback that will actually call the user specified
152 host lookup callback. This is executed back in the calling thread and
153 not in the lookup thread. */
155 SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
157 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
159 SILC_UNSET_HOST_LOOKUP(lookup->sock);
161 /* If the reference counter is 1 we know that we are the only one
162 holding the socket and it thus is considered freed. The lookup
163 is cancelled also and we will not call the final callback. */
164 if (lookup->sock->users == 1) {
165 SILC_LOG_DEBUG(("Async host lookup was cancelled"));
167 silc_socket_free(lookup->sock);
171 SILC_LOG_DEBUG(("Async host lookup finished"));
173 silc_socket_free(lookup->sock);
175 /* Call the final callback. */
176 if (lookup->callback)
177 lookup->callback(lookup->sock, lookup->context);
182 /* The thread function that performs the actual lookup. */
184 static void *silc_socket_host_lookup_start(void *context)
186 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
187 SilcSocketConnection sock = lookup->sock;
190 sock->port = silc_net_get_remote_port(sock->sock);
192 silc_net_check_host_by_sock(sock->sock, &sock->hostname, &sock->ip);
193 if (!sock->hostname && sock->ip)
194 sock->hostname = strdup(sock->ip);
196 silc_task_register(lookup->timeout_queue, sock->sock,
197 silc_socket_host_lookup_finish, lookup, 0, 1,
198 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
199 silc_task_queue_wakeup(lookup->timeout_queue);
204 /* Performs asynchronous host name and IP address lookups for the
205 specified socket connection. This may be called when the socket
206 connection is created and the full IP address and fully qualified
207 domain name information is desired. The `callback' with `context'
208 will be called after the lookup is performed. The `timeout_queue'
209 is the application's scheduler timeout queue which the lookup
210 routine needs. If the socket connection is freed during
211 the lookup the library will automatically cancel the lookup and
212 the `callback' will not be called. */
214 void silc_socket_host_lookup(SilcSocketConnection sock,
216 SilcSocketHostLookupCb callback,
220 SilcSocketHostLookup lookup;
222 SILC_LOG_DEBUG(("Performing async host lookup"));
227 lookup = silc_calloc(1, sizeof(*lookup));
228 lookup->sock = silc_socket_dup(sock); /* Increase reference counter */
229 lookup->callback = callback;
230 lookup->context = context;
231 lookup->timeout_queue = timeout_queue;
232 lookup->port = port_lookup;
234 SILC_SET_HOST_LOOKUP(sock);
236 silc_thread_create(silc_socket_host_lookup_start, lookup, FALSE);