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);
80 silc_free(sock->hostname);
82 memset(sock, 'F', sizeof(*sock));
87 /* Increase the reference counter. */
89 SilcSocketConnection silc_socket_dup(SilcSocketConnection sock)
92 SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users - 1,
97 /* Internal timeout callback to perform heartbeat */
99 SILC_TASK_CALLBACK(silc_socket_heartbeat)
101 SilcSocketConnectionHB hb = (SilcSocketConnectionHB)context;
106 if (SILC_IS_DISCONNECTING(hb->sock) ||
107 SILC_IS_DISCONNECTED(hb->sock))
111 hb->hb_callback(hb->sock, hb->hb_context);
113 hb->hb_task = silc_schedule_task_add(hb->schedule, hb->sock->sock,
114 silc_socket_heartbeat,
115 context, hb->heartbeat, 0,
120 /* Sets the heartbeat timeout and prepares the socket for performing
121 heartbeat in `heartbeat' intervals (seconds). The `hb_context' is
122 allocated by the application and will be sent as argument to the
123 `hb_callback' function that is called when the `heartbeat' timeout
124 expires. The callback `hb_context' won't be touched by the library
125 but will be freed automatically when calling silc_socket_free. The
126 `schedule' is the application's scheduler. */
128 void silc_socket_set_heartbeat(SilcSocketConnection sock,
129 SilcUInt32 heartbeat,
131 SilcSocketConnectionHBCb hb_callback,
132 SilcSchedule schedule)
135 silc_schedule_task_del(schedule, sock->hb->hb_task);
139 sock->hb = silc_calloc(1, sizeof(*sock->hb));
140 sock->hb->heartbeat = heartbeat;
141 sock->hb->hb_context = hb_context;
142 sock->hb->hb_callback = hb_callback;
143 sock->hb->schedule = schedule;
144 sock->hb->sock = sock;
145 sock->hb->hb_task = silc_schedule_task_add(schedule, sock->sock,
146 silc_socket_heartbeat,
147 (void *)sock->hb, heartbeat, 0,
152 /* Sets a "Quality of Service" settings for socket connection `sock'.
153 The `read_rate' specifies the maximum read operations per second.
154 If more read operations are executed the limit will be applied for
155 the reading. The `read_limit_bytes' specifies the maximum data
156 that is read. It is guaranteed that silc_socket_read never returns
157 more that `read_limit_bytes' of data. If more is read the limit
158 will be applied for the reading. The `limit_sec' and `limit_usec'
159 specifies the limit that is applied if `read_rate' and/or
160 `read_limit_bytes' is reached. The `schedule' is the application's
163 void silc_socket_set_qos(SilcSocketConnection sock,
164 SilcUInt32 read_rate,
165 SilcUInt32 read_limit_bytes,
166 SilcUInt32 limit_sec,
167 SilcUInt32 limit_usec,
168 SilcSchedule schedule)
171 sock->qos = silc_calloc(1, sizeof(*sock->qos));
175 sock->qos->read_rate = read_rate;
176 sock->qos->read_limit_bytes = read_limit_bytes;
177 sock->qos->limit_sec = limit_sec;
178 sock->qos->limit_usec = limit_usec;
179 sock->qos->schedule = schedule;
180 memset(&sock->qos->next_limit, 0, sizeof(sock->qos->next_limit));
181 sock->qos->cur_rate = 0;
184 /* Finishing timeout callback that will actually call the user specified
185 host lookup callback. This is executed back in the calling thread and
186 not in the lookup thread. */
188 SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
190 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
192 SILC_UNSET_HOST_LOOKUP(lookup->sock);
194 /* If the reference counter is 1 we know that we are the only one
195 holding the socket and it thus is considered freed. The lookup
196 is cancelled also and we will not call the final callback. */
197 if (lookup->sock->users == 1) {
198 SILC_LOG_DEBUG(("Async host lookup was cancelled"));
199 silc_socket_free(lookup->sock);
204 SILC_LOG_DEBUG(("Async host lookup finished"));
206 silc_socket_free(lookup->sock);
208 /* Call the final callback. */
209 if (lookup->callback)
210 lookup->callback(lookup->sock, lookup->context);
215 /* The thread function that performs the actual lookup. */
217 static void *silc_socket_host_lookup_start(void *context)
219 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
220 SilcSocketConnection sock = lookup->sock;
221 SilcSchedule schedule = lookup->schedule;
224 sock->port = silc_net_get_remote_port(sock->sock);
226 silc_net_check_host_by_sock(sock->sock, &sock->hostname, &sock->ip);
227 if (!sock->hostname && sock->ip)
228 sock->hostname = strdup(sock->ip);
230 silc_schedule_task_add(schedule, sock->sock,
231 silc_socket_host_lookup_finish, lookup, 0, 1,
232 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
233 silc_schedule_wakeup(schedule);
238 /* Performs asynchronous host name and IP address lookups for the
239 specified socket connection. This may be called when the socket
240 connection is created and the full IP address and fully qualified
241 domain name information is desired. The `callback' with `context'
242 will be called after the lookup is performed. The `schedule'
243 is the application's scheduler which the lookup routine needs. If
244 the socket connection is freed during the lookup the library will
245 automatically cancel the lookup and the `callback' will not be called. */
247 void silc_socket_host_lookup(SilcSocketConnection sock,
249 SilcSocketHostLookupCb callback,
251 SilcSchedule schedule)
253 SilcSocketHostLookup lookup;
255 SILC_LOG_DEBUG(("Performing async host lookup"));
257 if (SILC_IS_DISCONNECTING(sock) ||
258 SILC_IS_DISCONNECTED(sock))
261 lookup = silc_calloc(1, sizeof(*lookup));
262 lookup->sock = silc_socket_dup(sock); /* Increase reference counter */
263 lookup->callback = callback;
264 lookup->context = context;
265 lookup->schedule = schedule;
266 lookup->port = port_lookup;
268 SILC_SET_HOST_LOOKUP(sock);
269 silc_thread_create(silc_socket_host_lookup_start, lookup, FALSE);