5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2003 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.
21 #include "silcincludes.h"
23 /* Heartbeat context */
24 struct SilcSocketConnectionHBStruct {
26 SilcSocketConnectionHBCb hb_callback;
28 SilcSchedule schedule;
30 SilcSocketConnection sock;
33 /* Internal async host lookup context. */
35 SilcSocketHostLookupCb callback;
37 SilcSchedule schedule;
38 SilcSocketConnection sock;
40 } *SilcSocketHostLookup;
42 /* Allocates a new socket connection object. The allocated object is
43 returned to the new_socket argument. */
45 void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
46 SilcSocketConnection *new_socket)
48 SILC_LOG_DEBUG(("Allocating new socket connection object"));
50 /* Set the pointers. Incoming and outgoing data buffers
51 are allocated by the application when they are first used. */
52 *new_socket = silc_calloc(1, sizeof(**new_socket));
53 (*new_socket)->sock = sock;
54 (*new_socket)->type = type;
55 (*new_socket)->user_data = user_data;
56 (*new_socket)->protocol = NULL;
57 (*new_socket)->flags = 0;
58 (*new_socket)->inbuf = NULL;
59 (*new_socket)->outbuf = NULL;
60 (*new_socket)->users++;
63 /* Free's the Socket connection object. */
65 void silc_socket_free(SilcSocketConnection sock)
68 SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users + 1,
70 if (sock->users < 1) {
71 silc_buffer_free(sock->inbuf);
72 silc_buffer_free(sock->outbuf);
74 silc_schedule_task_del(sock->hb->schedule, sock->hb->hb_task);
78 silc_schedule_task_del_by_context(sock->qos->schedule, sock->qos);
82 silc_free(sock->hostname);
84 memset(sock, 'F', sizeof(*sock));
89 /* Increase the reference counter. */
91 SilcSocketConnection silc_socket_dup(SilcSocketConnection sock)
94 SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users - 1,
99 /* Internal timeout callback to perform heartbeat */
101 SILC_TASK_CALLBACK(silc_socket_heartbeat)
103 SilcSocketConnectionHB hb = (SilcSocketConnectionHB)context;
108 if (SILC_IS_DISCONNECTING(hb->sock) ||
109 SILC_IS_DISCONNECTED(hb->sock))
113 hb->hb_callback(hb->sock, hb->hb_context);
115 hb->hb_task = silc_schedule_task_add(hb->schedule, hb->sock->sock,
116 silc_socket_heartbeat,
117 context, hb->heartbeat, 0,
122 /* Sets the heartbeat timeout and prepares the socket for performing
123 heartbeat in `heartbeat' intervals (seconds). The `hb_context' is
124 allocated by the application and will be sent as argument to the
125 `hb_callback' function that is called when the `heartbeat' timeout
126 expires. The callback `hb_context' won't be touched by the library
127 but will be freed automatically when calling silc_socket_free. The
128 `schedule' is the application's scheduler. */
130 void silc_socket_set_heartbeat(SilcSocketConnection sock,
131 SilcUInt32 heartbeat,
133 SilcSocketConnectionHBCb hb_callback,
134 SilcSchedule schedule)
137 silc_schedule_task_del(schedule, sock->hb->hb_task);
141 sock->hb = silc_calloc(1, sizeof(*sock->hb));
142 sock->hb->heartbeat = heartbeat;
143 sock->hb->hb_context = hb_context;
144 sock->hb->hb_callback = hb_callback;
145 sock->hb->schedule = schedule;
146 sock->hb->sock = sock;
147 sock->hb->hb_task = silc_schedule_task_add(schedule, sock->sock,
148 silc_socket_heartbeat,
149 (void *)sock->hb, heartbeat, 0,
154 /* Sets a "Quality of Service" settings for socket connection `sock'.
155 The `read_rate' specifies the maximum read operations per second.
156 If more read operations are executed the limit will be applied for
157 the reading. The `read_limit_bytes' specifies the maximum data
158 that is read. It is guaranteed that silc_socket_read never returns
159 more that `read_limit_bytes' of data. If more is read the limit
160 will be applied for the reading. The `limit_sec' and `limit_usec'
161 specifies the limit that is applied if `read_rate' and/or
162 `read_limit_bytes' is reached. The `schedule' is the application's
165 void silc_socket_set_qos(SilcSocketConnection sock,
166 SilcUInt32 read_rate,
167 SilcUInt32 read_limit_bytes,
168 SilcUInt32 limit_sec,
169 SilcUInt32 limit_usec,
170 SilcSchedule schedule)
175 if (sock->qos && !read_rate && !read_limit_bytes &&
176 !limit_sec && !limit_usec && !schedule) {
177 silc_schedule_task_del_by_context(sock->qos->schedule, sock->qos);
178 silc_free(sock->qos);
186 sock->qos = silc_calloc(1, sizeof(*sock->qos));
190 sock->qos->read_rate = read_rate;
191 sock->qos->read_limit_bytes = read_limit_bytes;
192 sock->qos->limit_sec = limit_sec;
193 sock->qos->limit_usec = limit_usec;
194 sock->qos->schedule = schedule;
195 memset(&sock->qos->next_limit, 0, sizeof(sock->qos->next_limit));
196 sock->qos->cur_rate = 0;
197 sock->qos->sock = sock;
200 /* Finishing timeout callback that will actually call the user specified
201 host lookup callback. This is executed back in the calling thread and
202 not in the lookup thread. */
204 SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
206 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
208 SILC_UNSET_HOST_LOOKUP(lookup->sock);
210 /* If the reference counter is 1 we know that we are the only one
211 holding the socket and it thus is considered freed. The lookup
212 is cancelled also and we will not call the final callback. */
213 if (lookup->sock->users == 1) {
214 SILC_LOG_DEBUG(("Async host lookup was cancelled"));
215 silc_socket_free(lookup->sock);
220 SILC_LOG_DEBUG(("Async host lookup finished"));
222 silc_socket_free(lookup->sock);
224 /* Call the final callback. */
225 if (lookup->callback)
226 lookup->callback(lookup->sock, lookup->context);
231 /* The thread function that performs the actual lookup. */
233 static void *silc_socket_host_lookup_start(void *context)
235 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
236 SilcSocketConnection sock = lookup->sock;
237 SilcSchedule schedule = lookup->schedule;
240 sock->port = silc_net_get_remote_port(sock->sock);
242 silc_net_check_host_by_sock(sock->sock, &sock->hostname, &sock->ip);
243 if (!sock->hostname && sock->ip)
244 sock->hostname = strdup(sock->ip);
246 silc_schedule_task_add(schedule, sock->sock,
247 silc_socket_host_lookup_finish, lookup, 0, 1,
248 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
249 silc_schedule_wakeup(schedule);
254 /* Performs asynchronous host name and IP address lookups for the
255 specified socket connection. This may be called when the socket
256 connection is created and the full IP address and fully qualified
257 domain name information is desired. The `callback' with `context'
258 will be called after the lookup is performed. The `schedule'
259 is the application's scheduler which the lookup routine needs. If
260 the socket connection is freed during the lookup the library will
261 automatically cancel the lookup and the `callback' will not be called. */
263 void silc_socket_host_lookup(SilcSocketConnection sock,
265 SilcSocketHostLookupCb callback,
267 SilcSchedule schedule)
269 SilcSocketHostLookup lookup;
271 SILC_LOG_DEBUG(("Performing async host lookup"));
273 if (SILC_IS_DISCONNECTING(sock) ||
274 SILC_IS_DISCONNECTED(sock))
277 lookup = silc_calloc(1, sizeof(*lookup));
278 lookup->sock = silc_socket_dup(sock); /* Increase reference counter */
279 lookup->callback = callback;
280 lookup->context = context;
281 lookup->schedule = schedule;
282 lookup->port = port_lookup;
284 SILC_SET_HOST_LOOKUP(sock);
285 silc_thread_create(silc_socket_host_lookup_start, lookup, FALSE);