static connection_t *_accept_connection(void) { int sock; connection_t *con; char *ip; int serversock; serversock = wait_for_serversock(100); if(serversock < 0) return NULL; /* malloc enough room for a full IP address (including ipv6) */ ip = (char *)malloc(MAX_ADDR_LEN); sock = sock_accept(serversock, ip, MAX_ADDR_LEN); if (sock >= 0) { con = connection_create (sock, serversock, ip); if (con == NULL) free (ip); return con; } if (!sock_recoverable(sock_error())) WARN2("accept() failed with error %d: %s", sock_error(), strerror(sock_error())); free(ip); return NULL; }
static int connection_client_setup (connection_queue_t *node) { int err; err = -ENOENT; if (node->con->con_timeout <= time(NULL)) return err; global_lock(); err = client_create (&node->client, node->con, node->parser); if (err < 0) goto out_fail; if (sock_set_blocking (node->con->sock, 0) || sock_set_nodelay (node->con->sock)) { if (! sock_recoverable(sock_error())) { node->con->error = 1; err = -EINVAL; goto out_fail; } err = -EINPROGRESS; client_send_403 (node->client, "failed to set tcp options on client connection, dropping"); goto out_fail; } global_unlock(); return 0; out_fail: global_unlock(); return err; }
int sock_connected (sock_t sock, int timeout) { struct pollfd check; int val = SOCK_ERROR; socklen_t size = sizeof val; check.fd = sock; check.events = POLLOUT; switch (poll (&check, 1, timeout*1000)) { case 0: return SOCK_TIMEOUT; default: /* on windows getsockopt.val is defined as char* */ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*) &val, &size) == 0) { if (val == 0) return 1; sock_set_error (val); } /* fall through */ case -1: if (sock_recoverable (sock_error())) return 0; return SOCK_ERROR; } }
/* helper function for reading data from a client */ int client_read_bytes (client_t *client, void *buf, unsigned len) { int bytes; if (client->refbuf && client->refbuf->len) { /* we have data to read from a refbuf first */ if (client->refbuf->len < len) len = client->refbuf->len; memcpy (buf, client->refbuf->data, len); if (len < client->refbuf->len) { char *ptr = client->refbuf->data; memmove (ptr, ptr+len, client->refbuf->len - len); } client->refbuf->len -= len; return len; } bytes = sock_read_bytes (client->con->sock, buf, len); if (bytes > 0) return bytes; if (bytes < 0) { if (sock_recoverable (sock_error())) return -1; WARN0 ("source connection has died"); } client->con->error = 1; return -1; }
static void *log_commit_thread (void *arg) { INFO0 ("started"); while (1) { int ret = util_timed_wait_for_fd (logger_fd[0], 5000); if (ret == 0) continue; if (ret > 0) { char cm[80]; ret = pipe_read (logger_fd[0], cm, sizeof cm); if (ret > 0) { // fprintf (stderr, "logger woken with %d\n", ret); log_commit_entries (); continue; } } if (ret < 0 && sock_recoverable (sock_error())) continue; int err = sock_error(); sock_close (logger_fd[0]); sock_close (logger_fd[1]); if (worker_count) { worker_control_create (logger_fd); ERROR1 ("logger received code %d", err); continue; } // fprintf (stderr, "logger closed with zero workers\n"); break; } return NULL; }
/* handlers (default) for reading and writing a connection_t, no encrpytion * used just straight access to the socket */ int connection_read (connection_t *con, void *buf, size_t len) { int bytes = sock_read_bytes (con->sock, buf, len); if (bytes == 0) con->error = 1; if (bytes == -1 && !sock_recoverable (sock_error())) con->error = 1; return bytes; }
int connection_send (connection_t *con, const void *buf, size_t len) { int bytes = sock_write_bytes (con->sock, buf, len); if (bytes < 0) { if (!sock_recoverable (sock_error())) con->error = 1; } else con->sent_bytes += bytes; return bytes; }
/* determines if the passed socket is still connected */ int sock_active (sock_t sock) { char c; int l; l = recv (sock, &c, 1, MSG_PEEK); if (l == 0) return 0; if (l == SOCK_ERROR && sock_recoverable (sock_error())) return 1; return 0; }
/* helper function for sending the data to a client */ int client_send_bytes (client_t *client, const void *buf, unsigned len) { int ret = sock_write_bytes (client->con->sock, buf, len); if (ret < 0 && !sock_recoverable (sock_error())) { DEBUG0 ("Client connection died"); client->con->error = 1; } if (ret > 0) client->con->sent_bytes += ret; return ret; }
/* get some data from the source. The stream data is placed in a refbuf * and sent back, however NULL is also valid as in the case of a short * timeout and there's no data pending. */ static refbuf_t *get_next_buffer (source_t *source) { refbuf_t *refbuf = NULL; int delay = 250; if (source->short_delay) delay = 0; while (global.running == ICE_RUNNING && source->running) { int fds; time_t current = time (NULL); fds = util_timed_wait_for_fd (source->con->sock, delay); if (fds < 0) { if (! sock_recoverable (sock_error())) { WARN0 ("Error while waiting on socket, Disconnecting source"); source->running = 0; } break; } if (fds == 0) { if (source->last_read + (time_t)source->timeout < current) { DEBUG3 ("last %ld, timeout %ld, now %ld", source->last_read, source->timeout, current); WARN0 ("Disconnecting source due to socket timeout"); source->running = 0; } break; } source->last_read = current; refbuf = source->format->get_buffer (source); if (refbuf) break; } return refbuf; }
static connection_t *_accept_connection(int duration) { sock_t sock, serversock; char *ip; serversock = wait_for_serversock (duration); if (serversock == SOCK_ERROR) return NULL; /* malloc enough room for a full IP address (including ipv6) */ ip = (char *)malloc(MAX_ADDR_LEN); sock = sock_accept(serversock, ip, MAX_ADDR_LEN); if (sock != SOCK_ERROR) { connection_t *con = NULL; /* Make any IPv4 mapped IPv6 address look like a normal IPv4 address */ if (strncmp (ip, "::ffff:", 7) == 0) memmove (ip, ip+7, strlen (ip+7)+1); if (accept_ip_address (ip)) con = connection_create (sock, serversock, ip); if (con) return con; sock_close (sock); } else { if (!sock_recoverable(sock_error())) { WARN2("accept() failed with error %d: %s", sock_error(), strerror(sock_error())); thread_sleep (500000); } } free(ip); return NULL; }
int sock_connected (sock_t sock, int timeout) { fd_set wfds; int val = SOCK_ERROR; socklen_t size = sizeof val; struct timeval tv, *timeval = NULL; /* make a timeout of <0 be indefinite */ if (timeout >= 0) { tv.tv_sec = timeout; tv.tv_usec = 0; timeval = &tv; } FD_ZERO(&wfds); FD_SET(sock, &wfds); switch (select(sock + 1, NULL, &wfds, NULL, timeval)) { case 0: return SOCK_TIMEOUT; default: /* on windows getsockopt.val is defined as char* */ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*) &val, &size) == 0) { if (val == 0) return 1; sock_set_error (val); } /* fall through */ case -1: if (sock_recoverable (sock_error())) return 0; return SOCK_ERROR; } }
int connection_bufs_send (connection_t *con, struct connection_bufs *vectors, int skip) { IOVEC *p = vectors->block, old_vals; int i = vectors->count, offset = 0, ret = -1; i = connbufs_locate_start (vectors, skip, &old_vals, &offset); p = vectors->block + i; if (i >= 0) { if (not_ssl_connection (con)) { ret = sock_writev (con->sock, p, vectors->count - i); if (ret < 0 && !sock_recoverable (sock_error())) con->error = 1; } #ifdef HAVE_OPENSSL else { IOVEC *io = p; int bytes = 0; for (; i < vectors->count; i++, io++) { int v = connection_send_ssl (con, IO_VECTOR_BASE(io), IO_VECTOR_LEN(io)); if (v > 0) bytes += v; if (v < IO_VECTOR_LEN(io)) break; } if (bytes > 0) ret = bytes; } #endif if (offset) *p = old_vals; if (ret > 0) con->sent_bytes += ret; } return ret; }
/* main plugin handler for getting a buffer for the queue. In here we * just add an incoming page to the codecs and process it until either * more data is needed or we prodice a buffer for the queue. */ static refbuf_t *ogg_get_buffer (source_t *source) { ogg_state_t *ogg_info = source->format->_state; char *data = NULL; int bytes; while (1) { while (1) { ogg_page page; refbuf_t *refbuf; ogg_codec_t *codec = ogg_info->current; /* if a codec has just been given a page then process it */ if (codec && codec->process) { refbuf = codec->process (ogg_info, codec); if (refbuf) return complete_buffer (source, refbuf); ogg_info->current = NULL; } if (ogg_sync_pageout (&ogg_info->oy, &page) > 0) { if (ogg_page_bos (&page)) { process_initial_page (source->format, &page); continue; } ogg_info->bos_completed = 1; refbuf = process_ogg_page (ogg_info, &page); if (ogg_info->error) { ERROR0 ("Problem processing stream"); source->running = 0; return NULL; } if (refbuf) return complete_buffer (source, refbuf); continue; } /* need more stream data */ break; } /* we need more data to continue getting pages */ data = ogg_sync_buffer (&ogg_info->oy, 4096); bytes = sock_read_bytes (source->con->sock, data, 4096); if (bytes < 0) { if (sock_recoverable (sock_error())) return NULL; WARN0 ("source connection has died"); ogg_sync_wrote (&ogg_info->oy, 0); source->running = 0; return NULL; } if (bytes == 0) { INFO1 ("End of Stream %s", source->mount); ogg_sync_wrote (&ogg_info->oy, 0); source->running = 0; return NULL; } ogg_sync_wrote (&ogg_info->oy, bytes); } }
/* issue a connect, but return after the timeout (seconds) is reached. If * timeout is 0 or less then we will wait until the OS gives up on the connect * The socket is returned */ sock_t sock_connect_wto_bind (const char *hostname, int port, const char *bnd, int timeout) { sock_t sock = SOCK_ERROR; struct addrinfo *ai, *head, *b_head=NULL, hints; char service[8]; memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf (service, sizeof (service), "%u", port); if (getaddrinfo (hostname, service, &hints, &head)) return SOCK_ERROR; ai = head; while (ai) { int type = ai->ai_socktype; if ((sock = sock_open (ai->ai_family, type, ai->ai_protocol)) >= 0) { sock_set_cloexec (sock); if (timeout > 0) sock_set_blocking (sock, 0); if (bnd) { struct addrinfo b_hints; memset (&b_hints, 0, sizeof(b_hints)); b_hints.ai_family = ai->ai_family; b_hints.ai_socktype = ai->ai_socktype; b_hints.ai_protocol = ai->ai_protocol; if (getaddrinfo (bnd, NULL, &b_hints, &b_head) || bind (sock, b_head->ai_addr, b_head->ai_addrlen) < 0) { sock_close (sock); sock = SOCK_ERROR; break; } } if (connect (sock, ai->ai_addr, ai->ai_addrlen) == 0) break; /* loop as the connect maybe async */ while (sock != SOCK_ERROR) { if (sock_recoverable (sock_error())) { int connected = sock_connected (sock, timeout); if (connected == 0) /* try again, interrupted */ continue; if (connected == 1) /* connected */ { if (timeout >= 0) sock_set_blocking(sock, 1); break; } } sock_close (sock); sock = SOCK_ERROR; } if (sock != SOCK_ERROR) break; } ai = ai->ai_next; } if (b_head) freeaddrinfo (b_head); freeaddrinfo (head); return sock; }
static client_t *accept_client (void) { client_t *client = NULL; sock_t sock, serversock = wait_for_serversock (); char addr [200]; if (serversock == SOCK_ERROR) return NULL; sock = sock_accept (serversock, addr, 200); if (sock == SOCK_ERROR) { if (sock_recoverable (sock_error())) return NULL; WARN2 ("accept() failed with error %d: %s", sock_error(), strerror(sock_error())); thread_sleep (500000); return NULL; } do { int i, num; refbuf_t *r; if (sock_set_blocking (sock, 0) || sock_set_nodelay (sock)) { WARN0 ("failed to set tcp options on client connection, dropping"); break; } client = calloc (1, sizeof (client_t)); if (client == NULL || connection_init (&client->connection, sock, addr) < 0) break; client->shared_data = r = refbuf_new (PER_CLIENT_REFBUF_SIZE); r->len = 0; // for building up the request coming in global_lock (); client_register (client); for (i=0; i < global.server_sockets; i++) { if (global.serversock[i] == serversock) { client->server_conn = global.server_conn[i]; client->server_conn->refcount++; if (client->server_conn->ssl && ssl_ok) connection_uses_ssl (&client->connection); if (client->server_conn->shoutcast_compat) client->ops = &shoutcast_source_ops; else client->ops = &http_request_ops; break; } } num = global.clients; global_unlock (); stats_event_args (NULL, "clients", "%d", num); client->flags |= CLIENT_ACTIVE; return client; } while (0); free (client); sock_close (sock); return NULL; }
/* get some data from the source. The stream data is placed in a refbuf * and sent back, however NULL is also valid as in the case of a short * timeout and there's no data pending. */ static refbuf_t *get_next_buffer (source_t *source) { refbuf_t *refbuf = NULL; int delay = 250; if (source->short_delay) delay = 0; while (global.running == ICE_RUNNING && source->running) { int fds = 0; time_t current = time (NULL); if (source->client) fds = util_timed_wait_for_fd (source->con->sock, delay); else { thread_sleep (delay*1000); source->last_read = current; } if (current >= source->client_stats_update) { stats_event_args (source->mount, "total_bytes_read", "%"PRIu64, source->format->read_bytes); stats_event_args (source->mount, "total_bytes_sent", "%"PRIu64, source->format->sent_bytes); source->client_stats_update = current + 5; } if (fds < 0) { if (! sock_recoverable (sock_error())) { WARN0 ("Error while waiting on socket, Disconnecting source"); source->running = 0; } break; } if (fds == 0) { if (source->last_read + (time_t)source->timeout < current) { DEBUG3 ("last %ld, timeout %d, now %ld", (long)source->last_read, source->timeout, (long)current); WARN0 ("Disconnecting source due to socket timeout"); source->running = 0; } break; } source->last_read = current; refbuf = source->format->get_buffer (source); if (source->client->con && source->client->con->error) { INFO1 ("End of Stream %s", source->mount); source->running = 0; continue; } if (refbuf) break; } return refbuf; }