/src/rtpproxy/src/rtpp_notify.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2010-2014 Sippy Software, Inc., http://www.sippysoft.com |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * 1. Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * |
14 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
15 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
17 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
18 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
19 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
20 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
21 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
22 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
23 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
24 | | * SUCH DAMAGE. |
25 | | * |
26 | | */ |
27 | | |
28 | | #if defined(LINUX_XXX) && !defined(_GNU_SOURCE) |
29 | | #define _GNU_SOURCE /* pthread_setname_np() */ |
30 | | #endif |
31 | | |
32 | | #if defined(HAVE_CONFIG_H) |
33 | | #include "config_pp.h" |
34 | | #endif |
35 | | |
36 | | #include <sys/types.h> |
37 | | #include <sys/socket.h> |
38 | | #include <netinet/in.h> |
39 | | #include <assert.h> |
40 | | #include <errno.h> |
41 | | #include <pthread.h> |
42 | | #include <signal.h> |
43 | | #include <stddef.h> |
44 | | #include <stdio.h> |
45 | | #include <stdlib.h> |
46 | | #include <string.h> |
47 | | #include <unistd.h> |
48 | | |
49 | | #include "rtpp_log.h" |
50 | | #include "rtpp_types.h" |
51 | | #include "rtpp_codeptr.h" |
52 | | #include "rtpp_refcnt.h" |
53 | | #include "rtpp_log_obj.h" |
54 | | #include "rtpp_network.h" |
55 | | #include "rtpp_notify.h" |
56 | | #include "rtpp_queue.h" |
57 | | #include "rtpp_tnotify_tgt.h" |
58 | | #include "rtpp_mallocs.h" |
59 | | #include "rtpp_wi.h" |
60 | | #include "rtpp_wi_data.h" |
61 | | #include "rtpp_wi_sgnl.h" |
62 | | |
63 | | struct rtpp_notify_wi |
64 | | { |
65 | | int len; |
66 | | struct rtpp_tnotify_target *rttp; |
67 | | struct rtpp_log *glog; |
68 | | const char *ntype; |
69 | | char notify_buf[0]; |
70 | | }; |
71 | | |
72 | | struct rtpp_notify_priv { |
73 | | struct rtpp_notify pub; |
74 | | struct rtpp_queue *nqueue; |
75 | | struct rtpp_wi *sigterm; |
76 | | pthread_t thread_id; |
77 | | struct rtpp_log *glog; |
78 | | }; |
79 | | |
80 | | static int rtpp_notify_schedule(struct rtpp_notify *, |
81 | | struct rtpp_tnotify_target *, const rtpp_str_t *, const char *); |
82 | | static void rtpp_notify_dtor(struct rtpp_notify_priv *); |
83 | | static void do_notification(struct rtpp_notify_wi *, int); |
84 | | |
85 | | static void |
86 | | rtpp_notify_queue_run(void *arg) |
87 | 4 | { |
88 | 4 | struct rtpp_wi *wi; |
89 | 4 | struct rtpp_notify_wi *wi_data; |
90 | 4 | struct rtpp_notify_priv *pvt; |
91 | | |
92 | 4 | pvt = (struct rtpp_notify_priv *)arg; |
93 | 4 | for (;;) { |
94 | 4 | wi = rtpp_queue_get_item(pvt->nqueue, 0); |
95 | 4 | if (rtpp_wi_get_type(wi) == RTPP_WI_TYPE_SGNL) { |
96 | 4 | RTPP_OBJ_DECREF(wi); |
97 | 4 | break; |
98 | 4 | } |
99 | 0 | wi_data = rtpp_wi_data_get_ptr(wi, sizeof(struct rtpp_notify_wi), 0); |
100 | | |
101 | | /* main work here */ |
102 | 0 | do_notification(wi_data, 3); |
103 | | |
104 | | /* deallocate wi */ |
105 | 0 | RTPP_OBJ_DECREF(wi_data->glog); |
106 | 0 | RTPP_OBJ_DECREF(wi); |
107 | 0 | } |
108 | 4 | } |
109 | | |
110 | | struct rtpp_notify * |
111 | | rtpp_notify_ctor(struct rtpp_log *glog) |
112 | 4 | { |
113 | 4 | struct rtpp_notify_priv *pvt; |
114 | | |
115 | 4 | pvt = rtpp_rzmalloc(sizeof(struct rtpp_notify_priv), PVT_RCOFFS(pvt)); |
116 | 4 | if (pvt == NULL) { |
117 | 0 | goto e0; |
118 | 0 | } |
119 | 4 | pvt->nqueue = rtpp_queue_init(RTPQ_SMALL_CB_LEN, "rtpp_notify"); |
120 | 4 | if (pvt->nqueue == NULL) { |
121 | 0 | goto e1; |
122 | 0 | } |
123 | | |
124 | | /* Pre-allocate sigterm, so that we don't have any malloc() in dtor() */ |
125 | 4 | pvt->sigterm = rtpp_wi_malloc_sgnl(SIGTERM, NULL, 0); |
126 | 4 | if (pvt->sigterm == NULL) { |
127 | 0 | goto e2; |
128 | 0 | } |
129 | | |
130 | 4 | if (pthread_create(&pvt->thread_id, NULL, (void *(*)(void *))&rtpp_notify_queue_run, pvt) != 0) { |
131 | 0 | goto e3; |
132 | 0 | } |
133 | 4 | #if HAVE_PTHREAD_SETNAME_NP |
134 | 4 | (void)pthread_setname_np(pvt->thread_id, "rtpp_notify_queue"); |
135 | 4 | #endif |
136 | | |
137 | 4 | RTPP_OBJ_INCREF(glog); |
138 | 4 | pvt->glog = glog; |
139 | 4 | pvt->pub.schedule = &rtpp_notify_schedule; |
140 | | |
141 | 4 | RTPP_OBJ_DTOR_ATTACH_s(&pvt->pub, (rtpp_refcnt_dtor_t)&rtpp_notify_dtor, |
142 | 4 | pvt); |
143 | 4 | return (&pvt->pub); |
144 | | |
145 | 0 | e3: |
146 | 0 | RTPP_OBJ_DECREF(pvt->sigterm); |
147 | 0 | e2: |
148 | 0 | rtpp_queue_destroy(pvt->nqueue); |
149 | 0 | e1: |
150 | 0 | RTPP_OBJ_DECREF(&(pvt->pub)); |
151 | 0 | e0: |
152 | 0 | return (NULL); |
153 | 0 | } |
154 | | |
155 | | static void |
156 | | rtpp_notify_dtor(struct rtpp_notify_priv *pvt) |
157 | 4 | { |
158 | | |
159 | 4 | rtpp_queue_put_item(pvt->sigterm, pvt->nqueue); |
160 | 4 | pthread_join(pvt->thread_id, NULL); |
161 | 4 | rtpp_queue_destroy(pvt->nqueue); |
162 | 4 | RTPP_OBJ_DECREF(pvt->glog); |
163 | 4 | } |
164 | | |
165 | | static int |
166 | | rtpp_notify_schedule(struct rtpp_notify *pub, |
167 | | struct rtpp_tnotify_target *rttp, const rtpp_str_t *notify_tag, |
168 | | const char *notify_type) |
169 | 0 | { |
170 | 0 | struct rtpp_notify_wi *wi_data; |
171 | 0 | struct rtpp_wi *wi; |
172 | 0 | int len; |
173 | 0 | struct rtpp_notify_priv *pvt; |
174 | |
|
175 | 0 | PUB2PVT(pub, pvt); |
176 | | |
177 | | /* string, \0 and \n */ |
178 | 0 | len = notify_tag->len + 2; |
179 | |
|
180 | 0 | wi = rtpp_wi_malloc_udata((void **)&wi_data, |
181 | 0 | sizeof(struct rtpp_notify_wi) + len); |
182 | 0 | if (wi == NULL) { |
183 | 0 | return (-1); |
184 | 0 | } |
185 | 0 | memset(wi_data, '\0', sizeof(struct rtpp_notify_wi)); |
186 | |
|
187 | 0 | wi_data->rttp = rttp; |
188 | 0 | wi_data->len = len; |
189 | 0 | RTPP_OBJ_INCREF(pvt->glog); |
190 | 0 | wi_data->glog = pvt->glog; |
191 | 0 | wi_data->ntype = notify_type; |
192 | |
|
193 | 0 | memcpy(wi_data->notify_buf, notify_tag->s, notify_tag->len); |
194 | 0 | wi_data->notify_buf[notify_tag->len] = '\n'; |
195 | |
|
196 | 0 | rtpp_queue_put_item(wi, pvt->nqueue); |
197 | 0 | return (0); |
198 | 0 | } |
199 | | |
200 | | static void |
201 | | reconnect_handler(const struct rtpp_notify_wi *wi) |
202 | 0 | { |
203 | |
|
204 | 0 | assert (wi->rttp->connected == 0); |
205 | 0 | assert (wi->rttp->socket_type != RTPP_TNS_FD); |
206 | |
|
207 | 0 | if (wi->rttp->fd == -1) { |
208 | 0 | RTPP_LOG(wi->glog, RTPP_LOG_DBUG, "connecting %s socket", wi->ntype); |
209 | 0 | } else { |
210 | 0 | RTPP_LOG(wi->glog, RTPP_LOG_DBUG, "reconnecting %s socket", wi->ntype); |
211 | 0 | close(wi->rttp->fd); |
212 | 0 | } |
213 | 0 | wi->rttp->fd = socket(RTPP_TNT_STYPE(wi->rttp), SOCK_STREAM, 0); |
214 | 0 | if (wi->rttp->fd == -1) { |
215 | 0 | RTPP_ELOG(wi->glog, RTPP_LOG_ERR, "can't create %s socket", wi->ntype); |
216 | 0 | return; |
217 | 0 | } |
218 | 0 | if (wi->rttp->local != NULL) { |
219 | 0 | if (bind(wi->rttp->fd, wi->rttp->local, SA_LEN(wi->rttp->local)) < 0) { |
220 | 0 | RTPP_ELOG(wi->glog, RTPP_LOG_ERR, "can't bind %s socket", wi->ntype); |
221 | 0 | goto e0; |
222 | 0 | } |
223 | 0 | } |
224 | 0 | if (connect(wi->rttp->fd, (struct sockaddr *)&(wi->rttp->remote), wi->rttp->remote_len) == -1) { |
225 | 0 | RTPP_ELOG(wi->glog, RTPP_LOG_ERR, "can't connect to %s socket", wi->ntype); |
226 | 0 | goto e0; |
227 | 0 | } else { |
228 | 0 | wi->rttp->connected = 1; |
229 | 0 | } |
230 | 0 | return; |
231 | | |
232 | 0 | e0: |
233 | 0 | close(wi->rttp->fd); |
234 | 0 | wi->rttp->fd = -1; |
235 | 0 | return; |
236 | 0 | } |
237 | | |
238 | | static void |
239 | | do_notification(struct rtpp_notify_wi *wi, int retries) |
240 | 0 | { |
241 | 0 | int result; |
242 | |
|
243 | 0 | if (wi->rttp->connected == 0) { |
244 | 0 | reconnect_handler(wi); |
245 | | |
246 | | /* If connect fails, no notification will be sent */ |
247 | 0 | if (wi->rttp->connected == 0) { |
248 | 0 | RTPP_LOG(wi->glog, RTPP_LOG_ERR, "unable to send %s notification", |
249 | 0 | wi->ntype); |
250 | 0 | return; |
251 | 0 | } |
252 | 0 | } |
253 | | |
254 | 0 | do { |
255 | 0 | result = send(wi->rttp->fd, wi->notify_buf, wi->len - 1, 0); |
256 | 0 | } while (result == -1 && errno == EINTR); |
257 | |
|
258 | 0 | if (result < 0) { |
259 | 0 | wi->rttp->connected = 0; |
260 | 0 | RTPP_ELOG(wi->glog, RTPP_LOG_ERR, "failed to send %s notification", |
261 | 0 | wi->ntype); |
262 | 0 | if (retries > 0) |
263 | 0 | do_notification(wi, retries - 1); |
264 | 0 | } |
265 | 0 | } |