1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 /*
58 * heartbeat.c - thread for sending heartbeat Msgs to bearerbox
59 */
60
61 #include <signal.h>
62
63 #include "gwlib/gwlib.h"
64 #include "msg.h"
65 #include "heartbeat.h"
66
67 /*
68 * Each running heartbeat gets one of these. They are collected in
69 * the heartbeats List.
70 */
71 struct hb_info {
72 hb_send_func_t *send_func;
73 double freq;
74 hb_load_func_t *load_func;
75 long thread;
76 volatile sig_atomic_t running;
77 };
78
79 /* List of struct hb_info. */
80 static List *heartbeats = NULL;
81
82 /*
83 * Look for a hb_info in a list, by thread number.
84 */
find_hb(void * item,void * pattern)85 static int find_hb(void *item, void *pattern)
86 {
87 long *threadnrp;
88 struct hb_info *info;
89
90 info = item;
91 threadnrp = pattern;
92
93 return info->thread == *threadnrp;
94 }
95
heartbeat_thread(void * arg)96 static void heartbeat_thread(void *arg)
97 {
98 struct hb_info *info;
99 time_t last_hb;
100
101 info = arg;
102 last_hb = 0;
103
104 while (info->running) {
105 Msg *msg;
106
107 gwthread_sleep(info->freq);
108
109 /*
110 * Because the sleep can be interrupted, we might end up sending
111 * heartbeats faster than the configured heartbeat frequency.
112 * This is not bad unless we send them way too fast. Make sure
113 * our frequency is not more than twice the configured one.
114 */
115 if (difftime(time(NULL), last_hb) < info->freq / 2)
116 continue;
117
118 msg = msg_create(heartbeat);
119 if (NULL != info->load_func)
120 msg->heartbeat.load = info->load_func();
121 info->send_func(msg);
122 last_hb = time(NULL);
123 }
124 }
125
heartbeat_start(hb_send_func_t * send_func,double freq,hb_load_func_t * load_func)126 long heartbeat_start(hb_send_func_t *send_func, double freq,
127 hb_load_func_t *load_func)
128 {
129 struct hb_info *info;
130
131 /* can't start with send_funct NULL */
132 if (send_func == NULL)
133 return -1;
134
135 info = gw_malloc(sizeof(*info));
136 info->send_func = send_func;
137 info->freq = (freq <= 0 ? DEFAULT_HEARTBEAT : freq);
138 info->load_func = load_func;
139 info->running = 1;
140 info->thread = gwthread_create(heartbeat_thread, info);
141 if (info->thread >= 0) {
142 if (heartbeats == NULL)
143 heartbeats = gwlist_create();
144 gwlist_append(heartbeats, info);
145 return info->thread;
146 } else {
147 gw_free(info);
148 return -1;
149 }
150 }
151
152 /*
153 * function : heartbeat_stop
154 * arguments: long hb_thread, the thread number of the heartbeat
155 * that is wished to be stopped.
156 * if hb_thread == ALL_HEARTBEATS then all heartbeats
157 * are stopped.
158 * returns : -
159 */
heartbeat_stop(long hb_thread)160 void heartbeat_stop(long hb_thread)
161 {
162 List *matching_info;
163 struct hb_info *info;
164
165 /*
166 * First, check if there are heartbeats to stop.
167 * If not, do not continue, otherwise this function will crash
168 */
169 if (heartbeats == NULL)
170 return;
171
172 if (hb_thread == ALL_HEARTBEATS) {
173 while (NULL != (info = gwlist_extract_first(heartbeats))) {
174 gw_assert(info);
175 info->running = 0;
176 gwthread_wakeup(info->thread);
177 gwthread_join(info->thread);
178 gw_free(info);
179 }
180 } else {
181 matching_info = gwlist_extract_matching(heartbeats, &hb_thread, find_hb);
182 if (matching_info == NULL) {
183 warning(0, "Could not stop heartbeat %ld: not found.", hb_thread);
184 return;
185 }
186 gw_assert(gwlist_len(matching_info) == 1);
187 info = gwlist_extract_first(matching_info);
188 gwlist_destroy(matching_info, NULL);
189
190 info->running = 0;
191 gwthread_wakeup(hb_thread);
192 gwthread_join(hb_thread);
193 gw_free(info);
194 }
195 if (gwlist_len(heartbeats) == 0) {
196 gwlist_destroy(heartbeats, NULL);
197 heartbeats = NULL;
198 }
199 }
200