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;
107 hb->hb_callback(hb->sock, hb->hb_context);
109 hb->hb_task = silc_schedule_task_add(hb->schedule, hb->sock->sock,
110 silc_socket_heartbeat,
111 context, hb->heartbeat, 0,
116 /* Sets the heartbeat timeout and prepares the socket for performing
117 heartbeat in `heartbeat' intervals (seconds). The `hb_context' is
118 allocated by the application and will be sent as argument to the
119 `hb_callback' function that is called when the `heartbeat' timeout
120 expires. The callback `hb_context' won't be touched by the library
121 but will be freed automatically when calling silc_socket_free. The
122 `schedule' is the application's scheduler. */
124 void silc_socket_set_heartbeat(SilcSocketConnection sock,
125 SilcUInt32 heartbeat,
127 SilcSocketConnectionHBCb hb_callback,
128 SilcSchedule schedule)
131 silc_schedule_task_del(schedule, sock->hb->hb_task);
135 sock->hb = silc_calloc(1, sizeof(*sock->hb));
136 sock->hb->heartbeat = heartbeat;
137 sock->hb->hb_context = hb_context;
138 sock->hb->hb_callback = hb_callback;
139 sock->hb->schedule = schedule;
140 sock->hb->sock = sock;
141 sock->hb->hb_task = silc_schedule_task_add(schedule, sock->sock,
142 silc_socket_heartbeat,
143 (void *)sock->hb, heartbeat, 0,
148 /* Sets a "Quality of Service" settings for socket connection `sock'.
149 The `read_rate' specifies the maximum read operations per second.
150 If more read operations are executed the limit will be applied for
151 the reading. The `read_limit_bytes' specifies the maximum data
152 that is read. It is guaranteed that silc_socket_read never returns
153 more that `read_limit_bytes' of data. If more is read the limit
154 will be applied for the reading. The `limit_sec' and `limit_usec'
155 specifies the limit that is applied if `read_rate' and/or
156 `read_limit_bytes' is reached. The `schedule' is the application's
159 void silc_socket_set_qos(SilcSocketConnection sock,
160 SilcUInt32 read_rate,
161 SilcUInt32 read_limit_bytes,
162 SilcUInt32 limit_sec,
163 SilcUInt32 limit_usec,
164 SilcSchedule schedule)
167 sock->qos = silc_calloc(1, sizeof(*sock->qos));
171 sock->qos->read_rate = read_rate;
172 sock->qos->read_limit_bytes = read_limit_bytes;
173 sock->qos->limit_sec = limit_sec;
174 sock->qos->limit_usec = limit_usec;
175 sock->qos->schedule = schedule;
176 memset(&sock->qos->next_limit, 0, sizeof(sock->qos->next_limit));
177 sock->qos->cur_rate = 0;
180 /* Finishing timeout callback that will actually call the user specified
181 host lookup callback. This is executed back in the calling thread and
182 not in the lookup thread. */
184 SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
186 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
188 SILC_UNSET_HOST_LOOKUP(lookup->sock);
190 /* If the reference counter is 1 we know that we are the only one
191 holding the socket and it thus is considered freed. The lookup
192 is cancelled also and we will not call the final callback. */
193 if (lookup->sock->users == 1) {
194 SILC_LOG_DEBUG(("Async host lookup was cancelled"));
196 silc_socket_free(lookup->sock);
200 SILC_LOG_DEBUG(("Async host lookup finished"));
202 silc_socket_free(lookup->sock);
204 /* Call the final callback. */
205 if (lookup->callback)
206 lookup->callback(lookup->sock, lookup->context);
211 /* The thread function that performs the actual lookup. */
213 static void *silc_socket_host_lookup_start(void *context)
215 SilcSocketHostLookup lookup = (SilcSocketHostLookup)context;
216 SilcSocketConnection sock = lookup->sock;
217 SilcSchedule schedule = lookup->schedule;
220 sock->port = silc_net_get_remote_port(sock->sock);
222 silc_net_check_host_by_sock(sock->sock, &sock->hostname, &sock->ip);
223 if (!sock->hostname && sock->ip)
224 sock->hostname = strdup(sock->ip);
226 silc_schedule_task_add(schedule, sock->sock,
227 silc_socket_host_lookup_finish, lookup, 0, 1,
228 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
229 silc_schedule_wakeup(schedule);
234 /* Performs asynchronous host name and IP address lookups for the
235 specified socket connection. This may be called when the socket
236 connection is created and the full IP address and fully qualified
237 domain name information is desired. The `callback' with `context'
238 will be called after the lookup is performed. The `schedule'
239 is the application's scheduler which the lookup routine needs. If
240 the socket connection is freed during the lookup the library will
241 automatically cancel the lookup and the `callback' will not be called. */
243 void silc_socket_host_lookup(SilcSocketConnection sock,
245 SilcSocketHostLookupCb callback,
247 SilcSchedule schedule)
249 SilcSocketHostLookup lookup;
251 SILC_LOG_DEBUG(("Performing async host lookup"));
253 lookup = silc_calloc(1, sizeof(*lookup));
254 lookup->sock = silc_socket_dup(sock); /* Increase reference counter */
255 lookup->callback = callback;
256 lookup->context = context;
257 lookup->schedule = schedule;
258 lookup->port = port_lookup;
260 SILC_SET_HOST_LOOKUP(sock);
261 silc_thread_create(silc_socket_host_lookup_start, lookup, FALSE);