Skip to content

Commit 11fff2c

Browse files
committed
rtpproxy: drain timeout notification sockets
RTPProxy may keep the notification connection open while writing a burst of timeout events. The rtpproxy notification callback only performed a single read per reactor wakeup, so already-buffered notifications could be left pending with no further event to wake the process. Set notification sockets nonblocking and drain them until EAGAIN, preserving partial commands between callbacks. Also centralize notification connection cleanup so error, EOF and handler failure paths consistently unregister the fd, free pending data and close the socket.
1 parent 7ca3e56 commit 11fff2c

1 file changed

Lines changed: 123 additions & 60 deletions

File tree

modules/rtpproxy/notification_process.c

Lines changed: 123 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,44 @@ struct rtpp_notify {
5454
int fd;
5555
char *remaining;
5656
int remaining_len;
57+
int linked;
5758
union sockaddr_union addr;
5859
struct list_head list;
5960
};
6061
OSIPS_LIST_HEAD(rtpp_notify_fds);
6162

63+
static void free_rtpp_notify(int fd, struct rtpp_notify *notify)
64+
{
65+
reactor_del_reader(fd, -1, IO_FD_CLOSING);
66+
if (notify) {
67+
if (notify->linked)
68+
list_del(&notify->list);
69+
if (notify->remaining)
70+
pkg_free(notify->remaining);
71+
pkg_free(notify);
72+
}
73+
shutdown(fd, SHUT_RDWR);
74+
close(fd);
75+
}
76+
77+
static int set_nonblocking(int fd)
78+
{
79+
int flags;
80+
81+
flags = fcntl(fd, F_GETFL);
82+
if (flags == -1) {
83+
LM_ERR("fcntl(%d, F_GETFL) failed: %s\n", fd, strerror(errno));
84+
return -1;
85+
}
86+
87+
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
88+
LM_ERR("fcntl(%d, F_SETFL) failed: %s\n", fd, strerror(errno));
89+
return -1;
90+
}
91+
92+
return 0;
93+
}
94+
6295
static int notification_handler(str *command)
6396
{
6497
char cmd, *p;
@@ -200,7 +233,7 @@ static int rtpproxy_io_callback(int fd, void *fs, int was_timeout)
200233
{
201234
struct rtpp_notify *notify = (struct rtpp_notify *)fs;
202235
char buffer[BUF_LEN];
203-
int len, left, offset;
236+
int len, left, offset, total;
204237
str command;
205238
char *p, *start, *sp, *end;
206239

@@ -214,59 +247,79 @@ static int rtpproxy_io_callback(int fd, void *fs, int was_timeout)
214247
offset = 0;
215248
}
216249

217-
do
218-
len = read(fd, buffer + offset, BUF_LEN - offset);
219-
while (len == -1 && errno == EINTR);
220-
221-
if (len < 0) {
222-
LM_ERR("reading from socket failed: %s\n",strerror(errno));
223-
return -1;
224-
}
225-
if (len == 0) {
226-
LM_DBG("closing rtpproxy notify socket\n");
227-
reactor_del_reader(fd, -1, IO_FD_CLOSING);
228-
if (notify) {
229-
list_del(&notify->list);
230-
pkg_free(notify);
250+
for (;;) {
251+
if (offset == BUF_LEN) {
252+
LM_ERR("RTPProxy notification command too large [%.*s]\n",
253+
offset, buffer);
254+
free_rtpp_notify(fd, notify);
255+
return -1;
231256
}
232-
shutdown(fd, SHUT_RDWR);
233-
close(fd);
234-
return 0;
235-
}
236257

237-
LM_DBG("Notification(s) received: [%.*s]\n", len, buffer);
238-
p = buffer;
239-
left = len + offset;
240-
end = buffer + left;
258+
do
259+
len = read(fd, buffer + offset, BUF_LEN - offset);
260+
while (len == -1 && errno == EINTR);
241261

242-
do {
243-
start = p;
262+
if (len < 0) {
263+
if (errno == EAGAIN || errno == EWOULDBLOCK)
264+
break;
244265

245-
sp = q_memchr(p, '\n', left);
246-
if (sp == NULL)
247-
break;
248-
command.s = p;
249-
command.len = sp - p;
250-
/* skip the command */
251-
p = sp + 1;
252-
left -= (sp - start) + 1;
253-
254-
if (notification_handler(&command) < 0)
266+
LM_ERR("reading from socket failed: %s\n",strerror(errno));
267+
free_rtpp_notify(fd, notify);
255268
return -1;
269+
}
270+
if (len == 0) {
271+
if (offset)
272+
LM_WARN("dropping partial RTPProxy notification [%.*s]\n",
273+
offset, buffer);
274+
LM_DBG("closing rtpproxy notify socket\n");
275+
free_rtpp_notify(fd, notify);
276+
return 0;
277+
}
278+
279+
total = len + offset;
280+
LM_DBG("Notification(s) received: [%.*s]\n", total, buffer);
281+
p = buffer;
282+
left = total;
283+
end = buffer + total;
284+
285+
do {
286+
start = p;
287+
288+
sp = q_memchr(p, '\n', left);
289+
if (sp == NULL)
290+
break;
291+
command.s = p;
292+
command.len = sp - p;
293+
/* skip the command */
294+
p = sp + 1;
295+
left -= (sp - start) + 1;
296+
297+
if (notification_handler(&command) < 0) {
298+
LM_ERR("notification_handler failed\n");
299+
free_rtpp_notify(fd, notify);
300+
return -1;
301+
}
256302

257-
LM_DBG("Left to process: %d\n[%.*s]\n", left, left, p);
303+
LM_DBG("Left to process: %d\n[%.*s]\n", left, left, p);
258304

259-
} while (p < end);
305+
} while (p < end);
306+
307+
offset = end - p;
308+
if (offset) {
309+
LM_DBG("%d remaining data in buffer!\n", offset);
310+
memmove(buffer, p, offset);
311+
}
312+
}
260313

261-
if (end - p) {
262-
LM_DBG("%d remaining data in buffer!\n", (int)(end - start));
263-
if (notify && (notify->remaining = pkg_malloc(end - start)) != NULL) {
264-
notify->remaining_len = (int)(end - start);
265-
memcpy(notify->remaining, p, notify->remaining_len);
314+
if (offset) {
315+
if (notify && (notify->remaining = pkg_malloc(offset)) != NULL) {
316+
notify->remaining_len = offset;
317+
memcpy(notify->remaining, buffer, offset);
266318
} else {
267-
LM_WARN("dropping remaining data [%.*s]\n", (int)(end - start), start);
319+
LM_WARN("dropping remaining data [%.*s]\n", offset, buffer);
268320
}
269321
}
322+
270323
return 0;
271324
}
272325

@@ -285,35 +338,43 @@ static int rtpproxy_io_new_callback(int fd, void *fs, int was_timeout)
285338
return -1;
286339
}
287340

288-
if (rtpp_notify_socket_un) {
289-
LM_DBG("trusting unix socket connection\n");
290-
if (reactor_proc_add_fd(fd, rtpproxy_io_callback, NULL)<0) {
291-
LM_CRIT("failed to add RTPProxy new connection to reactor\n");
292-
return -1;
293-
}
294-
return 0;
295-
}
296-
node = rtpproxy_get_node((union sockaddr_union *)&rtpp_info);
297-
if (!node) {
298-
LM_WARN("connection from unknown RTPProxy node");
299-
return -1;
300-
}
341+
if (set_nonblocking(fd) < 0)
342+
goto err;
301343

302344
notify = pkg_malloc(sizeof *notify);
303345
if (!notify) {
304346
LM_ERR("could not allocate notify node\n");
305-
return -1;
347+
goto err;
306348
}
307349
memset(notify, 0, sizeof *notify);
308350
notify->fd = fd;
309-
memcpy(&notify->addr, &node->addr, sizeof(union sockaddr_union));
351+
352+
if (rtpp_notify_socket_un) {
353+
LM_DBG("trusting unix socket connection\n");
354+
} else {
355+
node = rtpproxy_get_node((union sockaddr_union *)&rtpp_info);
356+
if (!node) {
357+
LM_WARN("connection from unknown RTPProxy node");
358+
pkg_free(notify);
359+
goto err;
360+
}
361+
memcpy(&notify->addr, &node->addr, sizeof(union sockaddr_union));
362+
list_add(&notify->list, &rtpp_notify_fds);
363+
notify->linked = 1;
364+
}
365+
310366
if (reactor_proc_add_fd(fd, rtpproxy_io_callback, notify) < 0) {
311367
LM_CRIT("failed to add RTPProxy listen socket to reactor\n");
368+
if (notify->linked)
369+
list_del(&notify->list);
312370
pkg_free(notify);
313-
return -1;
371+
goto err;
314372
}
315-
list_add(&notify->list, &rtpp_notify_fds);
316373
return 0;
374+
err:
375+
shutdown(fd, SHUT_RDWR);
376+
close(fd);
377+
return -1;
317378
}
318379

319380
int init_rtpp_notify(void)
@@ -411,6 +472,8 @@ void notification_listener_process(int rank)
411472
return;
412473
}
413474

475+
if (set_nonblocking(socket_fd) < 0)
476+
return;
414477
if (reactor_proc_add_fd( socket_fd, rtpproxy_io_new_callback, NULL) < 0) {
415478
LM_CRIT("failed to add RTPProxy listen socket to reactor\n");
416479
return;

0 commit comments

Comments
 (0)