Logo Search packages:      
Sourcecode: icecast-server version File versions  Download package


/* connection.c
 * - Connection functions
 * Copyright (c) 1999 Jack Moffitt, Barath Raghavan, and Alexander Havšng
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

#ifdef _WIN32
#include <win32config.h>
#include <config.h>

#include "definitions.h"
#include <stdio.h>
#include "definitions.h"

#include <signal.h>

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include <unistd.h>

#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h>

#ifndef _WIN32
#include <sys/socket.h> 
#include <sys/wait.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <winsock.h>

#include "avl.h"
#include "threads.h"
#include "icetypes.h"
#include "icecast.h"
#include "utility.h"
#include "ice_string.h"
#include "connection.h"
#include "log.h"
#include "ice_resolv.h"
#include "sock.h"
#include "client.h"
#include "source.h"
#include "admin.h"
#include "logtime.h"
#include "restrict.h"
#include "memory.h"
#include "http.h"
#include "vars.h"
#include "commands.h"

extern server_info_t info;
const char cnull[] = "(null)";

 * This is called to handle a brand new connection, in it's own thread.
 * We know nothing about the type of the connection.
 * Assert Class: 3
void *handle_connection(void *arg)
      connection_t *con = (connection_t *)arg;
      char line[BUFSIZE] = "";
      int res;


      if (!con) {
            write_log(LOG_DEFAULT, "handle_connection: got NULL connection");

      if (info.reverse_lookups)
            con->hostname = reverse(con->host);
      if (!allowed_no_policy (con, unknown_connection_e)) {
            write_http_code_page(con, 403, "Forbidden");
            kick_not_connected(con, "Access Denied (internal acl list (generic connection))");

      sock_set_blocking(con->sock, SOCK_BLOCK);
      /* Fill line[] with the user header, ends with \n\n */
      if ((res = sock_read_lines(con->sock, line, BUFSIZE)) <= 0) {
            write_log(LOG_DEFAULT, "Socket error on connection %d", con->id);
            kick_not_connected(con, "Socket error");
      if (res == 2) /* stupid xaudio */
            strncpy(line, "GET / HTTP/1.0\nUser-Agent:stupid-xaudio\n\n", BUFSIZE);
       * Check if it's a client, admin or source.
       * Client connections will return,
       * Admin and source will run as its own thread
       * and never return.
      if (ice_strncmp(line, "GET", 3) == 0) {
            client_login(con, line);
      } else if (ice_strncmp(line, "ADMIN", 5) == 0) {
            admin_login(con, line);
      } else if (ice_strncmp(line, "SOURCE", 5) == 0) {
            source_login (con, line);
      } else if (ice_strncmp(line, "PING", 4) == 0) {
            thread_rename("PING Handler Thread");
            line[1] = 'O';
            sock_write_line (con->sock, "%s", line);
            xa_debug (1, "Replied to ping from [%s]", con_host(con));
      } else {
            char pass[BUFSIZE];
            if (splitc(pass, line, '\n') || (strncpy(pass, line, BUFSIZE))) {
                  if (pass[ice_strlen(pass) - 1] == '\n')
                        pass[ice_strlen(pass) - 1] = '\0';
                  if (password_match(info.encoder_pass, pass)) {
                        char newline[BUFSIZE + 20];
                        sock_write_line (con->sock, "OK2");
                        sock_write_line (con->sock, "icy-caps:11\r\n");
                        if ((res = sock_read_lines_np(con->sock, line, BUFSIZE)) <= 0) {
                              write_log(LOG_DEFAULT, "Socket error on connection %d", con->id);
                              kick_not_connected(con, "Socket error");
                        con->food.source->protocol = icy_e;
                        con->food.source->type = encoder_e;
                        snprintf(newline, BUFSIZE+20, "SOURCE %s %s\n%s", pass, next_mount_point(), line);
                        source_login(con, newline);
            /* Client said something we didn't recognize. */
            write_http_code_page (con, 306, "Grow up");
            kick_not_connected(con, "Stupid headers");
      return NULL;

connection_t *
      connection_t *con = (connection_t *) nmalloc (sizeof (connection_t));
      con->type = unknown_connection_e;
      con->headervars = NULL;
      con->sin = NULL;
      con->hostname = NULL;
      con->headervars = NULL;
      con->food.source = NULL;
      return con;

connection_t *
get_connection (sock_t *sock)
      int sockfd;
      socklen_t sin_len;
      connection_t *con;
      fd_set rfds;
      struct timeval tv;
      int i, maxport = 0;
      struct sockaddr_in *sin = (struct sockaddr_in *)nmalloc(sizeof(struct sockaddr_in));

      /* PARANOIA here */
      if (!sin)
            write_log (LOG_DEFAULT, "WARNING: Weird stuff in get_connection. nmalloc returned NULL sin");
            return NULL;

      /* setup sockaddr structure */
      sin_len = sizeof(struct sockaddr_in);
      memset(sin, 0, sin_len);
      /* try to accept a connection */
      for (i = 0; i < MAXLISTEN; i++) {
            if (sock_valid (sock[i])) {
                  FD_SET(sock[i], &rfds);
                  if (sock[i] > maxport) 
                        maxport = sock[i];
      maxport += 1;

      tv.tv_sec = 0;
      tv.tv_usec = 30000;

      if (select(maxport, &rfds, NULL, NULL, &tv) > 0) {
            for (i = 0; i < MAXLISTEN; i++) {
                  if (sock_valid (sock[i]) && FD_ISSET(sock[i], &rfds)) 
      } else {
            return NULL;
      sockfd = sock_accept(sock[i], (struct sockaddr *)sin, &sin_len);
      if (sockfd >= 0) {
            con = create_connection();
            if (!sin)
                  xa_debug (1, "ERROR: NULL sockaddr struct, wft???");
                  return NULL;

            con->host = create_malloced_ascii_host(&(sin->sin_addr));
            con->sock = sockfd;
            con->sin = sin;
            con->sinlen = sin_len;
            xa_debug (2, "DEBUG: Getting new connection on socket %d from host %s", sockfd, con->host ? con->host : "(null)");
            con->hostname = NULL;
            con->headervars = NULL;
            con->id = new_id ();
            con->connect_time = get_time ();
            if (!sock_check_libwrap(sockfd, unknown_connection_e))
                  kick_not_connected (con, "Access Denied (tcp wrappers) [generic connection]");
                  return NULL;

            return con; /* We got a one */

      /* FIXME (don't use strerror) */
      if (!is_recoverable (errno))
            xa_debug (1, "WARNING: accept() failed with on socket %d, max: %d, [%d:%s]", sock[i], maxport, 
                    errno, strerror(errno));
      nfree (sin);
      return NULL;

describe_connection (const com_request_t *req, const connection_t *describecon)
      char buf[BUFSIZE];
      avl_traverser trav = {0};
      const varpair_t *vp;

      if (!req || !describecon)
            xa_debug (1, "WARNING: describe_connection() called with NULL pointers");

      admin_write_line (req, ADMIN_SHOW_DESCRIBE_CON_START, "Connection info");

      admin_write_line (req, ADMIN_SHOW_DESCRIBE_CON_MISC, "Connection id: %lu", describecon->id);
      admin_write_line (req, ADMIN_SHOW_DESCRIBE_CON_MISC, "Connection socket: %d", describecon->sock);
      admin_write_line (req, ADMIN_SHOW_DESCRIBE_CON_MISC, "Connect time: %s", nice_time (get_time () - describecon->connect_time, buf));
      admin_write_line (req, ADMIN_SHOW_DESCRIBE_CON_MISC, "Connection host and ip: %s [%s]", describecon->hostname ? describecon->hostname : "(null)", describecon->host);
      if (describecon->headervars)
            admin_write_line (req, ADMIN_SHOW_DESCRIBE_CON_HEADERS_START, "Header variables:");
            while ((vp = avl_traverse (describecon->headervars, &trav)))
                  admin_write_line (req, ADMIN_SHOW_DESCRIBE_CON_HEADERS_ENTRY, "'%s' = '%s'", vp->name, vp->value);
            admin_write_line (req, ADMIN_SHOW_DESCRIBE_CON_HEADERS_END, "End of header variable listing");

      admin_write_line (req, ADMIN_SHOW_DESCRIBE_CON_END, "End of connection info");

const char *
get_user_agent (connection_t *con)
      const char *res;

      if (!con)
            return cnull;

      res = get_con_variable (con, "User-Agent");

      if (!res)
            res = get_con_variable (con, "User-agent");

      if (!res)
            res = get_con_variable (con, "user-agent");

        if (!res)
            return cnull;
            return res;

build_source_con_line_with_opts (connection_t *con, char *line, int *opt, int maxlen)
      char buf[BUFSIZE];

      line[0] = '\0';
      buf[0] = '\0';

      /* Build the line */
      if (opt[SOURCE_SHOW_ID])
            catsnprintf (line, BUFSIZE, "[Id: %d] ", con->id);
      if (opt[SOURCE_SHOW_SOCKET])
            catsnprintf (line, BUFSIZE, "[Sock: %d] ", con->sock);
      if (opt[SOURCE_SHOW_CTIME])
        char *ct = get_string_time (con->connect_time, REGULAR_TIME);
        catsnprintf (line, BUFSIZE, "[Time of connect: %s] ", ct);
        if (ct)
              free (ct);
      if (opt[SOURCE_SHOW_IP] && con->host)
            catsnprintf (line, BUFSIZE, "[IP: %s] ", con->host);
      if (opt[SOURCE_SHOW_HOST] && con->hostname)
            catsnprintf (line, BUFSIZE, "[Host: %s] ", con->hostname);
      if (opt[SOURCE_SHOW_STATE])
            catsnprintf (line, BUFSIZE, "[State: %d] ", con->food.source->connected);
      if (opt[SOURCE_SHOW_TYPE])
            catsnprintf (line, BUFSIZE, "[Type: %s] ", sourcetype_to_string (con->food.source->type));
      if (opt[SOURCE_SHOW_PROTO])
            catsnprintf (line, BUFSIZE, "[Proto: %s] ", sourceproto_to_string (con->food.source->protocol));
      if (opt[SOURCE_SHOW_CLIENTS])
            catsnprintf (line, BUFSIZE, "[Clients: %d] ", con->food.source->num_clients);
      if (opt[SOURCE_SHOW_DUMPFILE])
            catsnprintf (line, BUFSIZE, "[Dumpfile/fd: %s/%d] ", nullcheck_string (con->food.source->dumpfile), con->food.source->dumpfd);
      if (opt[SOURCE_SHOW_PRIO])
            catsnprintf (line, BUFSIZE, "[Priority: %d] ", con->food.source->priority);
      if (opt[SOURCE_SHOW_SONG_TITLE])
            catsnprintf (line, BUFSIZE, "[Song Title: %s] ", nullcheck_string (con->food.source->info.streamtitle));
      if (opt[SOURCE_SHOW_SONG_URL])
            catsnprintf (line, BUFSIZE, "[Song URL: %s] ", nullcheck_string (con->food.source->info.streamurl));
      if (opt[SOURCE_SHOW_STREAM_MSG])
            catsnprintf (line, BUFSIZE, "[Stream Message: %s] ", nullcheck_string (con->food.source->info.streammsg));
            catsnprintf (line, BUFSIZE, "[Song Length: %ld bytes] ", con->food.source->info.streamlength);
      if (opt[SOURCE_SHOW_NAME])
            catsnprintf (line, BUFSIZE, "[Stream Name: %s] ", nullcheck_string (con->food.source->audiocast.name));
      if (opt[SOURCE_SHOW_GENRE])
            catsnprintf (line, BUFSIZE, "[Stream Genre: %s] ", nullcheck_string (con->food.source->audiocast.genre));
      if (opt[SOURCE_SHOW_BITRATE])
            catsnprintf (line, BUFSIZE, "[Stream Bitrate: %d] ", con->food.source->audiocast.bitrate);
      if (opt[SOURCE_SHOW_URL])
            catsnprintf (line, BUFSIZE, "[Stream URL: %s] ", nullcheck_string (con->food.source->audiocast.url));
      if (opt[SOURCE_SHOW_MOUNT])
            catsnprintf (line, BUFSIZE, "[Mountpoint: %s] ", nullcheck_string (con->food.source->audiocast.mount));
      if (opt[SOURCE_SHOW_DESC])
            catsnprintf (line, BUFSIZE, "[Description: %s] ", nullcheck_string (con->food.source->audiocast.description));
      if (opt[SOURCE_SHOW_READ])
            catsnprintf (line, BUFSIZE, "[MBytes read: %lu] ", con->food.source->stats.read_megs);
      if (opt[SOURCE_SHOW_WRITTEN])
            catsnprintf (line, BUFSIZE, "[MBytes written: %lu] ", con->food.source->stats.write_megs);
      if (opt[SOURCE_SHOW_CONNECTS])
            catsnprintf (line, BUFSIZE, "[Client connections: %lu] ", con->food.source->stats.client_connections);
      if (opt[SOURCE_SHOW_TIME])
            catsnprintf (line, BUFSIZE, "[Connected for: %s] ", nice_time (get_time() - con->connect_time, buf));

Generated by  Doxygen 1.6.0   Back to index