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;
29 SilcSchedule schedule;
31 SilcSocketConnection sock;
34 /* Internal async host lookup context. */
36 SilcSocketHostLookupCb callback;
38 SilcSchedule schedule;
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_schedule_task_del(sock->hb->schedule, sock->hb->hb_task);
76 silc_free(sock->hb->hb_context);
81 silc_free(sock->hostname);
83 memset(sock, 'F', sizeof(*sock));
88 /* Increase the reference counter. */
90 SilcSocketConnection silc_socket_dup(SilcSocketConnection sock)
93 SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users - 1,
98 /* Internal timeout callback to perform heartbeat */
100 SILC_TASK_CALLBACK(silc_socket_heartbeat)
102 SilcSocketConnectionHB hb = (SilcSocketConnectionHB)context;
108 hb->hb_callback(hb->sock, hb->hb_context);
110 hb->hb_task = silc_schedule_task_add(hb->schedule, hb->sock->sock,
111 silc_socket_heartbeat,
112 context, hb->heartbeat, 0,
117 /* Sets the heartbeat timeout and prepares the socket for performing
118 heartbeat in `heartbeat' intervals (seconds). The `hb_context' is
119 allocated by the application and will be sent as argument to the
120 `hb_callback' function that is called when the `heartbeat' timeout
121 expires. The callback `hb_context' won't be touched by the library
122 but will be freed automatically when calling silc_socket_free. The
123 `schedule' is the application's scheduler. */
125 void silc_socket_set_heartbeat(SilcSocketConnection sock,
128 SilcSocketConnectionHBCb hb_callback,
129 SilcSchedule schedule)
132 silc_schedule_task_del(schedule, sock->hb->hb_task);
133 silc_free(sock->hb->hb_context);
137 sock->hb = silc_calloc(1, sizeof(*sock->hb));
138 sock->hb->heartbeat = heartbeat;
139 sock->hb->hb_context = hb_context;
140 sock->hb->hb_callback = hb_callback;
141 sock->hb->schedule = schedule;
142 sock->hb->sock = sock;
143 sock->hb->hb_task = silc_schedule_task_add(schedule, sock->sock,
144 silc_socket_heartbeat,
145 (void *)sock->hb, heartbeat, 0,
150 /* Finishing timeout callback that will actually call the user specified
151 host lookup callback. This is executed back in the calling thread and
152 not in the lookup thread. */
154 SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
156 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
158 SILC_UNSET_HOST_LOOKUP(lookup->sock);
160 /* If the reference counter is 1 we know that we are the only one
161 holding the socket and it thus is considered freed. The lookup
162 is cancelled also and we will not call the final callback. */
163 if (lookup->sock->users == 1) {
164 SILC_LOG_DEBUG(("Async host lookup was cancelled"));
166 silc_socket_free(lookup->sock);
170 SILC_LOG_DEBUG(("Async host lookup finished"));
172 silc_socket_free(lookup->sock);
174 /* Call the final callback. */
175 if (lookup->callback)
176 lookup->callback(lookup->sock, lookup->context);
181 /* The thread function that performs the actual lookup. */
183 static void *silc_socket_host_lookup_start(void *context)
185 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
186 SilcSocketConnection sock = lookup->sock;
189 sock->port = silc_net_get_remote_port(sock->sock);
191 silc_net_check_host_by_sock(sock->sock, &sock->hostname, &sock->ip);
192 if (!sock->hostname && sock->ip)
193 sock->hostname = strdup(sock->ip);
195 silc_schedule_task_add(lookup->schedule, sock->sock,
196 silc_socket_host_lookup_finish, lookup, 0, 1,
197 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
198 silc_schedule_wakeup(lookup->schedule);
203 /* Performs asynchronous host name and IP address lookups for the
204 specified socket connection. This may be called when the socket
205 connection is created and the full IP address and fully qualified
206 domain name information is desired. The `callback' with `context'
207 will be called after the lookup is performed. The `schedule'
208 is the application's scheduler which the lookup routine needs. If
209 the socket connection is freed during the lookup the library will
210 automatically cancel the lookup and the `callback' will not be called. */
212 void silc_socket_host_lookup(SilcSocketConnection sock,
214 SilcSocketHostLookupCb callback,
216 SilcSchedule schedule)
218 SilcSocketHostLookup lookup;
220 SILC_LOG_DEBUG(("Performing async host lookup"));
222 lookup = silc_calloc(1, sizeof(*lookup));
223 lookup->sock = silc_socket_dup(sock); /* Increase reference counter */
224 lookup->callback = callback;
225 lookup->context = context;
226 lookup->schedule = schedule;
227 lookup->port = port_lookup;
229 SILC_SET_HOST_LOOKUP(sock);
230 silc_thread_create(silc_socket_host_lookup_start, lookup, FALSE);