updates.
[silc.git] / lib / silcutil / silcsockconn.c
1 /*
2
3   silcsockconn.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2001 Pekka Riikonen
8
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.
13   
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.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23
24 /* Heartbeat context */
25 struct SilcSocketConnectionHB {
26   uint32 heartbeat;
27   SilcSocketConnectionHBCb hb_callback;
28   void *hb_context;
29   void *timeout_queue;
30   SilcTask hb_task;
31   SilcSocketConnection sock;
32 };
33
34 /* Allocates a new socket connection object. The allocated object is 
35    returned to the new_socket argument. */
36
37 void silc_socket_alloc(int sock, SilcSocketType type, void *user_data, 
38                        SilcSocketConnection *new_socket)
39 {
40   SILC_LOG_DEBUG(("Allocating new socket connection object"));
41
42   /* Set the pointers. Incoming and outgoing data buffers
43      are allocated by the application when they are first used. */
44   *new_socket = silc_calloc(1, sizeof(**new_socket));
45   (*new_socket)->sock = sock;
46   (*new_socket)->type = type;
47   (*new_socket)->user_data = user_data;
48   (*new_socket)->protocol = NULL;
49   (*new_socket)->flags = 0;
50   (*new_socket)->inbuf = NULL;
51   (*new_socket)->outbuf = NULL;
52   (*new_socket)->users++;
53 }
54
55 /* Free's the Socket connection object. */
56
57 void silc_socket_free(SilcSocketConnection sock)
58 {
59   sock->users--;
60   SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users + 1,
61                   sock->users));
62   if (sock->users < 1) {
63     silc_buffer_free(sock->inbuf);
64     silc_buffer_free(sock->outbuf);
65     if (sock->hb) {
66       silc_task_unregister(sock->hb->timeout_queue, sock->hb->hb_task);
67       silc_free(sock->hb->hb_context);
68       silc_free(sock->hb);
69     }
70
71     memset(sock, 'F', sizeof(*sock));
72     silc_free(sock);
73   }
74 }
75
76 /* Increase the reference counter. */
77
78 SilcSocketConnection silc_socket_dup(SilcSocketConnection sock)
79 {
80   sock->users++;
81   SILC_LOG_DEBUG(("Socket %p refcnt %d->%d", sock, sock->users - 1,
82                   sock->users));
83   return sock;
84 }
85
86 /* Internal timeout callback to perform heartbeat */
87
88 SILC_TASK_CALLBACK(silc_socket_heartbeat)
89 {
90   SilcSocketConnectionHB hb = (SilcSocketConnectionHB)context;
91
92   if (!hb->heartbeat)
93     return;
94
95   if (hb->hb_callback)
96     hb->hb_callback(hb->sock, hb->hb_context);
97
98   hb->hb_task = silc_task_register(hb->timeout_queue, hb->sock->sock, 
99                                    silc_socket_heartbeat,
100                                    context, hb->heartbeat, 0,
101                                    SILC_TASK_TIMEOUT,
102                                    SILC_TASK_PRI_LOW);
103 }
104
105 /* Sets the heartbeat timeout and prepares the socket for performing
106    heartbeat in `heartbeat' intervals (seconds). The `hb_context' is
107    allocated by the application and will be sent as argument to the
108    `hb_callback' function that is called when the `heartbeat' timeout
109    expires.  The callback `hb_context' won't be touched by the library
110    but will be freed automatically when calling silc_socket_free.  The
111    `timeout_queue' is the application's scheduler timeout queue. */
112
113 void silc_socket_set_heartbeat(SilcSocketConnection sock, 
114                                uint32 heartbeat,
115                                void *hb_context,
116                                SilcSocketConnectionHBCb hb_callback,
117                                void *timeout_queue)
118 {
119
120   if (sock->hb) {
121     silc_task_unregister(sock->hb->timeout_queue, sock->hb->hb_task);
122     silc_free(sock->hb->hb_context);
123     silc_free(sock->hb);
124   }
125
126   sock->hb = silc_calloc(1, sizeof(*sock->hb));
127   sock->hb->heartbeat = heartbeat;
128   sock->hb->hb_context = hb_context;
129   sock->hb->hb_callback = hb_callback;
130   sock->hb->timeout_queue = timeout_queue;
131   sock->hb->sock = sock;
132   sock->hb->hb_task = silc_task_register(timeout_queue, sock->sock,
133                                          silc_socket_heartbeat,
134                                          (void *)sock->hb, heartbeat, 0,
135                                          SILC_TASK_TIMEOUT,
136                                          SILC_TASK_PRI_LOW);
137 }