[xiph-cvs] cvs commit: icecast/src connection.c

Jack Moffitt jack at xiph.org
Fri Mar 22 14:41:17 PST 2002



jack        02/03/22 14:41:17

  Modified:    src      connection.c
  Log:
  Ouch.  Serious bug found by Ricardo Galli.
  
  When the cond var is signalled it will wake up a thread.  If all the
  connection handler threads are handling connections, the signal will be
  ignored and clients will 'pend' until another client causes the to signal
  again.
  
  We have to check to see if there are more pending connections before waiting
  on the signal again.

Revision  Changes    Path
1.9       +173 -174  icecast/src/connection.c

Index: connection.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/connection.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- connection.c	2002/02/11 09:11:17	1.8
+++ connection.c	2002/03/22 22:41:16	1.9
@@ -310,161 +310,140 @@
                 if (global.running != ICE_RUNNING) break;
 
                 /* grab a connection and set the socket to blocking */
-		con = _get_connection();
+		while (con = _get_connection()) {
+			stats_event_inc(NULL, "connections");
 
-		stats_event_inc(NULL, "connections");
+			sock_set_blocking(con->sock, SOCK_BLOCK);
 
-		sock_set_blocking(con->sock, SOCK_BLOCK);
-
-		/* fill header with the http header */
-		if (util_read_header(con->sock, header, 4096) == 0) {
-			/* either we didn't get a complete header, or we timed out */
-			connection_close(con);
-			continue;
-		}
-
-		parser = httpp_create_parser();
-		httpp_initialize(parser, NULL);
-		if (httpp_parse(parser, header, strlen(header))) {
-			/* handle the connection or something */
-
-			if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) != 0 && strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) != 0) {
-				printf("DEBUG: bad protocol\n");
+			/* fill header with the http header */
+			if (util_read_header(con->sock, header, 4096) == 0) {
+				/* either we didn't get a complete header, or we timed out */
                                 connection_close(con);
-				httpp_destroy(parser);
                                 continue;
                         }
 
-			if (parser->req_type == httpp_req_source) {
-                char *contenttype;
-
-				printf("DEBUG: source logging in\n");
-				stats_event_inc(NULL, "source_connections");
+			parser = httpp_create_parser();
+			httpp_initialize(parser, NULL);
+			if (httpp_parse(parser, header, strlen(header))) {
+				/* handle the connection or something */
                                 
-				if (strcmp((httpp_getvar(parser, "ice-password") != NULL) ? httpp_getvar(parser, "ice-password") : "", (config_get_config()->source_password != NULL) ? config_get_config()->source_password : "") != 0) {
-					printf("DEBUG: bad password\n");
-					INFO1("Source (%s) attempted to login with bad password", httpp_getvar(parser, HTTPP_VAR_URI));
+				if (strcmp("ICE", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) != 0 && strcmp("HTTP", httpp_getvar(parser, HTTPP_VAR_PROTOCOL)) != 0) {
+					printf("DEBUG: bad protocol\n");
                                         connection_close(con);
                                         httpp_destroy(parser);
                                         continue;
                                 }
 
-				/* check to make sure this source has
-				** a unique mountpoint
-				*/
-
-				avl_tree_rlock(global.source_tree);
-				if (source_find_mount(httpp_getvar(parser, HTTPP_VAR_URI)) != NULL) {
-					printf("Source attempted to connect with an already used mountpoint.\n");
-					INFO1("Source tried to log in as %s, but is already used", httpp_getvar(parser, HTTPP_VAR_URI));
-					connection_close(con);
-					httpp_destroy(parser);
+				if (parser->req_type == httpp_req_source) {
+					char *contenttype;
+
+					printf("DEBUG: source logging in\n");
+					stats_event_inc(NULL, "source_connections");
+				
+					if (strcmp((httpp_getvar(parser, "ice-password") != NULL) ? httpp_getvar(parser, "ice-password") : "", (config_get_config()->source_password != NULL) ? config_get_config()->source_password : "") != 0) {
+						printf("DEBUG: bad password\n");
+						INFO1("Source (%s) attempted to login with bad password", httpp_getvar(parser, HTTPP_VAR_URI));
+						connection_close(con);
+						httpp_destroy(parser);
+						continue;
+					}
+
+					/* check to make sure this source has
+					** a unique mountpoint
+					*/
+
+					avl_tree_rlock(global.source_tree);
+					if (source_find_mount(httpp_getvar(parser, HTTPP_VAR_URI)) != NULL) {
+						printf("Source attempted to connect with an already used mountpoint.\n");
+						INFO1("Source tried to log in as %s, but is already used", httpp_getvar(parser, HTTPP_VAR_URI));
+						connection_close(con);
+						httpp_destroy(parser);
+						avl_tree_unlock(global.source_tree);
+						continue;
+					}
                                         avl_tree_unlock(global.source_tree);
-					continue;
-				}
-				avl_tree_unlock(global.source_tree);
 
-				/* check to make sure this source wouldn't
-				** be over the limit
-				*/
-				global_lock();
-				if (global.sources >= config_get_config()->source_limit) {
-					printf("TOO MANY SOURCE, KICKING THIS ONE\n");
-					INFO1("Source (%s) logged in, but there are too many sources", httpp_getvar(parser, HTTPP_VAR_URI));
-					connection_close(con);
-					httpp_destroy(parser);
+					/* check to make sure this source wouldn't
+					** be over the limit
+					*/
+					global_lock();
+					if (global.sources >= config_get_config()->source_limit) {
+						printf("TOO MANY SOURCE, KICKING THIS ONE\n");
+						INFO1("Source (%s) logged in, but there are too many sources", httpp_getvar(parser, HTTPP_VAR_URI));
+						connection_close(con);
+						httpp_destroy(parser);
+						global_unlock();
+						continue;
+					}
+					global.sources++;
                                         global_unlock();
-					continue;
-				}
-				global.sources++;
-				global_unlock();
+					
+					stats_event_inc(NULL, "sources");
 
-				stats_event_inc(NULL, "sources");
+					contenttype = httpp_getvar(parser, "content-type");
 
-                contenttype = httpp_getvar(parser, "content-type");
-
-				if (contenttype != NULL) {
-                    format_type_t format = format_get_type(contenttype);
-                    if(format < 0) {
-                        WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
-                        continue;
-                    }
-                    else
-				        source = source_create(con, parser, httpp_getvar(parser, HTTPP_VAR_URI), format);
-                }
-                else {
-                    WARN0("No content-type header, cannot handle source");
-                    continue;
-                }
+					if (contenttype != NULL) {
+						format_type_t format = format_get_type(contenttype);
+						if (format < 0) {
+							WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
+							continue;
+						} else {
+							source = source_create(con, parser, httpp_getvar(parser, HTTPP_VAR_URI), format);
+						}
+					} else {
+						WARN0("No content-type header, cannot handle source");
+						continue;
+					}
 
-				source->shutdown_rwlock = &_source_shutdown_rwlock;
+					source->shutdown_rwlock = &_source_shutdown_rwlock;
 
-				sock_set_blocking(con->sock, SOCK_NONBLOCK);
+					sock_set_blocking(con->sock, SOCK_NONBLOCK);
                                 
-				thread_create("Source Thread", source_main, (void *)source, THREAD_DETACHED);
+					thread_create("Source Thread", source_main, (void *)source, THREAD_DETACHED);
                                 
-				continue;
-			} else if (parser->req_type == httpp_req_stats) {
-				printf("DEBUG: stats connection...\n");
-				stats_event_inc(NULL, "stats_connections");
-
-				if (strcmp((httpp_getvar(parser, "ice-password") != NULL) ? httpp_getvar(parser, "ice-password") : "", (config_get_config()->source_password != NULL) ? config_get_config()->source_password : "") != 0) {
-					printf("DEBUG: bad password\n");
-					connection_close(con);
-					httpp_destroy(parser);
-					continue;
-				}
-
-				stats_event_inc(NULL, "stats");
-
-				/* create stats connection and create stats handler thread */
-				stats = (stats_connection_t *)malloc(sizeof(stats_connection_t));
-				stats->parser = parser;
-				stats->con = con;
-
-				thread_create("Stats Connection", stats_connection, (void *)stats, THREAD_DETACHED);
-
-				continue;
-			} else if (parser->req_type == httpp_req_play || parser->req_type == httpp_req_get) {
-				printf("DEBUG: client coming in...\n");
-
-				/* make a client */
-				client = client_create(con, parser);
-				stats_event_inc(NULL, "client_connections");
-
-				/* there are several types of HTTP GET clients
-				** media clients, which are looking for a source (eg, URI = /stream.ogg)
-				** stats clients, which are looking for /stats.xml
-				** and director server authorizers, which are looking for /GUID-xxxxxxxx (where xxxxxx is the GUID in question
-				** we need to handle the latter two before the former, as the latter two
-				** aren't subject to the limits.
-				*/
-				// TODO: add GUID-xxxxxx
-				if (strcmp(httpp_getvar(parser, HTTPP_VAR_URI), "/stats.xml") == 0) {
-					printf("sending stats.xml\n");
-					stats_sendxml(client);
                                         continue;
-				}
-
-				global_lock();
-				if (global.clients >= config_get_config()->client_limit) {
-					if (parser->req_type == httpp_req_get) {
-						client->respcode = 504;
-						bytes = sock_write(client->con->sock, "HTTP/1.0 504 Server Full\r\nContent-Type: text/html\r\n\r\n"\
-								   "<b>The server is already full.  Try again later.</b>\r\n");
-						if (bytes > 0) client->con->sent_bytes = bytes;
+				} else if (parser->req_type == httpp_req_stats) {
+					printf("DEBUG: stats connection...\n");
+					stats_event_inc(NULL, "stats_connections");
+					
+					if (strcmp((httpp_getvar(parser, "ice-password") != NULL) ? httpp_getvar(parser, "ice-password") : "", (config_get_config()->source_password != NULL) ? config_get_config()->source_password : "") != 0) {
+						printf("DEBUG: bad password\n");
+						connection_close(con);
+						httpp_destroy(parser);
+						continue;
                                         }
-					client_destroy(client);
-					global_unlock();
-					continue;
-				}
-				global_unlock();
-				
-				avl_tree_rlock(global.source_tree);
-				source = source_find_mount(httpp_getvar(parser, HTTPP_VAR_URI));
-				if (source) {
-					printf("DEBUG: source found for client\n");
-
+					
+					stats_event_inc(NULL, "stats");
+					
+					/* create stats connection and create stats handler thread */
+					stats = (stats_connection_t *)malloc(sizeof(stats_connection_t));
+					stats->parser = parser;
+					stats->con = con;
+					
+					thread_create("Stats Connection", stats_connection, (void *)stats, THREAD_DETACHED);
+					
+					continue;
+				} else if (parser->req_type == httpp_req_play || parser->req_type == httpp_req_get) {
+					printf("DEBUG: client coming in...\n");
+
+					/* make a client */
+					client = client_create(con, parser);
+					stats_event_inc(NULL, "client_connections");
+					
+					/* there are several types of HTTP GET clients
+					** media clients, which are looking for a source (eg, URI = /stream.ogg)
+					** stats clients, which are looking for /stats.xml
+					** and director server authorizers, which are looking for /GUID-xxxxxxxx (where xxxxxx is the GUID in question
+					** we need to handle the latter two before the former, as the latter two
+					** aren't subject to the limits.
+					*/
+					// TODO: add GUID-xxxxxx
+					if (strcmp(httpp_getvar(parser, HTTPP_VAR_URI), "/stats.xml") == 0) {
+						printf("sending stats.xml\n");
+						stats_sendxml(client);
+						continue;
+					}
+					
                                         global_lock();
                                         if (global.clients >= config_get_config()->client_limit) {
                                                 if (parser->req_type == httpp_req_get) {
@@ -477,60 +456,80 @@
                                                 global_unlock();
                                                 continue;
                                         }
-					global.clients++;
                                         global_unlock();
-
-					if (parser->req_type == httpp_req_get) {
-						client->respcode = 200;
-						sock_write(client->con->sock, "HTTP/1.0 200 OK\r\nContent-Type: application/x-ogg\r\n");
-						/* iterate through source http headers and send to client */
-						avl_tree_rlock(source->parser->vars);
-						node = avl_get_first(source->parser->vars);
-						while (node) {
-						        var = (http_var_t *)node->key;
-							if (strcasecmp(var->name, "ice-password") && !strncasecmp("ice-", var->name, 4)) {
-								printf("DEBUG: sending %s: %s\n", var->name, var->value);
-								sock_write(client->con->sock, "%s: %s\r\n", var->name, var->value);
+					
+					avl_tree_rlock(global.source_tree);
+					source = source_find_mount(httpp_getvar(parser, HTTPP_VAR_URI));
+					if (source) {
+						printf("DEBUG: source found for client\n");
+						
+						global_lock();
+						if (global.clients >= config_get_config()->client_limit) {
+							if (parser->req_type == httpp_req_get) {
+								client->respcode = 504;
+								bytes = sock_write(client->con->sock, "HTTP/1.0 504 Server Full\r\nContent-Type: text/html\r\n\r\n"\
+										   "<b>The server is already full.  Try again later.</b>\r\n");
+								if (bytes > 0) client->con->sent_bytes = bytes;
                                                         }
-							node = avl_get_next(node);
+							client_destroy(client);
+							global_unlock();
+							continue;
                                                 }
-						avl_tree_unlock(source->parser->vars);
-
-						sock_write(client->con->sock, "\r\n");
+						global.clients++;
+						global_unlock();
+						
+						if (parser->req_type == httpp_req_get) {
+							client->respcode = 200;
+							sock_write(client->con->sock, "HTTP/1.0 200 OK\r\nContent-Type: application/x-ogg\r\n");
+							/* iterate through source http headers and send to client */
+							avl_tree_rlock(source->parser->vars);
+							node = avl_get_first(source->parser->vars);
+							while (node) {
+								var = (http_var_t *)node->key;
+								if (strcasecmp(var->name, "ice-password") && !strncasecmp("ice-", var->name, 4)) {
+									printf("DEBUG: sending %s: %s\n", var->name, var->value);
+									sock_write(client->con->sock, "%s: %s\r\n", var->name, var->value);
+								}
+								node = avl_get_next(node);
+							}
+							avl_tree_unlock(source->parser->vars);
+							
+							sock_write(client->con->sock, "\r\n");
+							
+							sock_set_blocking(client->con->sock, SOCK_NONBLOCK);
+						}
                                                 
-						sock_set_blocking(client->con->sock, SOCK_NONBLOCK);
+						avl_tree_wlock(source->pending_tree);
+						avl_insert(source->pending_tree, (void *)client);
+						avl_tree_unlock(source->pending_tree);
                                         }
-
-					avl_tree_wlock(source->pending_tree);
-					avl_insert(source->pending_tree, (void *)client);
-					avl_tree_unlock(source->pending_tree);
-				}
-				
-				avl_tree_unlock(global.source_tree);
-				
-				if (!source) {
-					printf("DEBUG: source not found for client\n");
-					if (parser->req_type == httpp_req_get) {
-						client->respcode = 404;
-						bytes = sock_write(client->con->sock, "HTTP/1.0 404 Source Not Found\r\nContent-Type: text/html\r\n\r\n"\
-							"<b>The source you requested could not be found.</b>\r\n");
-						if (bytes > 0) client->con->sent_bytes = bytes;
+					
+					avl_tree_unlock(global.source_tree);
+					
+					if (!source) {
+						printf("DEBUG: source not found for client\n");
+						if (parser->req_type == httpp_req_get) {
+							client->respcode = 404;
+							bytes = sock_write(client->con->sock, "HTTP/1.0 404 Source Not Found\r\nContent-Type: text/html\r\n\r\n"\
+									   "<b>The source you requested could not be found.</b>\r\n");
+							if (bytes > 0) client->con->sent_bytes = bytes;
+						}
+						client_destroy(client);
                                         }
-					client_destroy(client);
+					
+					continue;
+				} else {
+					printf("DEBUG: wrong request type\n");
+					connection_close(con);
+					httpp_destroy(parser);
+					continue;
                                 }
-				
-				continue;
                         } else {
-				printf("DEBUG: wrong request type\n");
+				printf("DEBUG: parsing failed\n");
                                 connection_close(con);
                                 httpp_destroy(parser);
                                 continue;
                         }
-		} else {
-			printf("DEBUG: parsing failed\n");
-			connection_close(con);
-			httpp_destroy(parser);
-			continue;
                 }
         }
 

<p><p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list