gst/tcp/gstmultifdsink.*: Recover from a select with a bad file descriptor by removing the client.

Original commit message from CVS:
* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
(gst_multifdsink_add), (gst_multifdsink_remove),
(gst_multifdsink_clear), (gst_multifdsink_get_stats),
(gst_multifdsink_client_remove),
(gst_multifdsink_handle_client_write),
(gst_multifdsink_queue_buffer), (gst_multifdsink_handle_clients):
* gst/tcp/gstmultifdsink.h:
Recover from a select with a bad file descriptor by removing
the client.
This commit is contained in:
Wim Taymans 2004-07-30 16:17:37 +00:00
parent 9d0344af8c
commit 8a0309661a
3 changed files with 85 additions and 30 deletions

View file

@ -1,3 +1,15 @@
2004-07-30 Wim Taymans <wim@fluendo.com>
* gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
(gst_multifdsink_add), (gst_multifdsink_remove),
(gst_multifdsink_clear), (gst_multifdsink_get_stats),
(gst_multifdsink_client_remove),
(gst_multifdsink_handle_client_write),
(gst_multifdsink_queue_buffer), (gst_multifdsink_handle_clients):
* gst/tcp/gstmultifdsink.h:
Recover from a select with a bad file descriptor by removing
the client.
2004-07-30 Thomas Vander Stichele <thomas at apestaart dot org> 2004-07-30 Thomas Vander Stichele <thomas at apestaart dot org>
* configure.ac: * configure.ac:

View file

@ -302,9 +302,12 @@ gst_multifdsink_add (GstMultiFdSink * sink, int fd)
GstTCPClient *client; GstTCPClient *client;
GTimeVal now; GTimeVal now;
GST_DEBUG_OBJECT (sink, "adding client on fd %d", fd);
/* create client datastructure */ /* create client datastructure */
client = g_new0 (GstTCPClient, 1); client = g_new0 (GstTCPClient, 1);
client->fd = fd; client->fd = fd;
client->bad = FALSE;
client->bufpos = -1; client->bufpos = -1;
client->bufoffset = 0; client->bufoffset = 0;
client->sending = NULL; client->sending = NULL;
@ -340,6 +343,8 @@ gst_multifdsink_remove (GstMultiFdSink * sink, int fd)
{ {
GList *clients; GList *clients;
GST_DEBUG_OBJECT (sink, "removing client on fd %d", fd);
g_mutex_lock (sink->clientslock); g_mutex_lock (sink->clientslock);
/* loop over the clients to find the one with the fd */ /* loop over the clients to find the one with the fd */
for (clients = sink->clients; clients; clients = g_list_next (clients)) { for (clients = sink->clients; clients; clients = g_list_next (clients)) {
@ -358,6 +363,8 @@ gst_multifdsink_remove (GstMultiFdSink * sink, int fd)
void void
gst_multifdsink_clear (GstMultiFdSink * sink) gst_multifdsink_clear (GstMultiFdSink * sink)
{ {
GST_DEBUG_OBJECT (sink, "clearing all clients");
g_mutex_lock (sink->clientslock); g_mutex_lock (sink->clientslock);
while (sink->clients) { while (sink->clients) {
GstTCPClient *client; GstTCPClient *client;
@ -918,41 +925,70 @@ gst_multifdsink_handle_clients (GstMultiFdSink * sink)
/* < 0 is an error, 0 just means a timeout happened */ /* < 0 is an error, 0 just means a timeout happened */
if (result < 0) { if (result < 0) {
GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL), GST_WARNING_OBJECT (sink, "select failed: %s", g_strerror (errno));
("select failed: %s", g_strerror (errno))); if (errno == EBADF) {
return; /* ok, so one of the fds is invalid. We loop over them to find one
} * that gives an error to the F_GETFL fcntl.
*/
g_mutex_lock (sink->clientslock);
for (clients = sink->clients; clients; clients = g_list_next (clients)) {
GstTCPClient *client;
int fd;
long flags;
int res;
GST_LOG_OBJECT (sink, "%d sockets had action", result); client = (GstTCPClient *) clients->data;
GST_LOG_OBJECT (sink, "done select on server/client fds for reads"); fd = client->fd;
gst_multifdsink_debug_fdset (sink, &testreadfds);
GST_LOG_OBJECT (sink, "done select on client fds for writes");
gst_multifdsink_debug_fdset (sink, &testwritefds);
/* read all commands */ res = fcntl (fd, F_GETFL, &flags);
if (FD_ISSET (READ_SOCKET (sink), &testreadfds)) { if (res == -1) {
while (TRUE) { GST_WARNING_OBJECT (sink, "fnctl failed for %d, marking as bad: %s",
gchar command; fd, g_strerror (errno));
int res; if (errno == EBADF) {
client->bad = TRUE;
READ_COMMAND (sink, command, res); }
if (res < 0) { }
/* no more commands */
break;
} }
g_mutex_unlock (sink->clientslock);
} else if (errno == EINTR) {
try_again = TRUE;
} else {
GST_ELEMENT_ERROR (sink, RESOURCE, READ, (NULL),
("select failed: %s", g_strerror (errno)));
return;
}
} else {
GST_LOG_OBJECT (sink, "%d sockets had action", result);
GST_LOG_OBJECT (sink, "done select on server/client fds for reads");
gst_multifdsink_debug_fdset (sink, &testreadfds);
GST_LOG_OBJECT (sink, "done select on client fds for writes");
gst_multifdsink_debug_fdset (sink, &testwritefds);
switch (command) { /* read all commands */
case CONTROL_RESTART: if (FD_ISSET (READ_SOCKET (sink), &testreadfds)) {
/* need to restart the select call as the fd_set changed */ while (TRUE) {
try_again = TRUE; gchar command;
break; int res;
case CONTROL_STOP:
/* stop this function */ READ_COMMAND (sink, command, res);
stop = TRUE; if (res < 0) {
break; /* no more commands */
default:
g_warning ("multifdsink: unknown control message received");
break; break;
}
switch (command) {
case CONTROL_RESTART:
/* need to restart the select call as the fd_set changed */
try_again = TRUE;
break;
case CONTROL_STOP:
/* stop this function */
stop = TRUE;
break;
default:
g_warning ("multifdsink: unknown control message received");
break;
}
} }
} }
} }
@ -971,6 +1007,11 @@ gst_multifdsink_handle_clients (GstMultiFdSink * sink)
int fd; int fd;
client = (GstTCPClient *) clients->data; client = (GstTCPClient *) clients->data;
if (client->bad) {
error = g_list_prepend (error, client);
continue;
}
fd = client->fd; fd = client->fd;
if (FD_ISSET (fd, &testreadfds)) { if (FD_ISSET (fd, &testreadfds)) {

View file

@ -81,6 +81,8 @@ typedef struct {
int fd; int fd;
gint bufpos; /* position of this client in the global queue */ gint bufpos; /* position of this client in the global queue */
gboolean bad;
GList *sending; /* the buffers we need to send */ GList *sending; /* the buffers we need to send */
gint bufoffset; /* offset in the first buffer */ gint bufoffset; /* offset in the first buffer */