crossroads

Git mirror of https://crossroads.e-tunity.com/
git clone git://git.finwo.net/app/crossroads
Log | Files | Refs

tcpserve.c (4945B)


      1 /*************************************************************************
      2  * This file is part of Crosroads 1.23, a load balancer and fail over
      3  * utility for TCP. Copyright (c) Karel Kubat, distributed under GPL.
      4  * Visit http://crossroads.e-tunity.com for information.
      5  *************************************************************************/
      6 #include "crossroads.h"
      7 
      8 void tcpserve (int server_sock) {
      9     fd_set set;
     10     int backend_sock, new, size, i, pid, backend_selected;
     11     struct sockaddr_in clientname;
     12     static int wakeup_started = 0;
     13 
     14     /* Set up our signal handlers. */
     15     if (!wakeup_started++) {
     16 	/* Interruption signals */
     17 	for (i = 0; relevant_sigs[i]; i++)
     18 	    signal (relevant_sigs[i], interrupt);
     19 	/* Child termination is ignored. */
     20 	signal (SIGCHLD, SIG_IGN);
     21 	/* Set wakeup handler for the wakeup calls. */
     22 	if (activeservice->rev_interval) {
     23 	    if ( (pid = fork()) < 0 )
     24 		error ("Fork failed: %s", strerror(errno));
     25 	    else if (!pid) {
     26 		set_program_title ("Service %s: wakeup", activeservice->name);
     27 		wakeup_handler();
     28 	    } else {
     29 		msg ("Service %s: started wakeup handler at pid %d",
     30 		     activeservice->name, pid);
     31 		servicereport->rev_pid = pid;
     32 	    }
     33 	}
     34     }
     35     
     36     msg ("Service %s: awaiting activity on port %d (socket fd %d)",
     37 	 activeservice->name, activeservice->port, server_sock);
     38 
     39     if (listen (server_sock, activeservice->backlog + 1) < 0)
     40 	error ("Service %s: failed to listen to server_socket: %s",
     41 	       activeservice->name, strerror(errno));
     42     
     43     /* We're a service now. Never return, never exit
     44      * (unless something is REALLY wrong).
     45      */
     46     while (1) {
     47 	/* Block until we get a connection. */
     48 	FD_ZERO (&set);
     49 	FD_SET (server_sock, &set);
     50 	if (select (FD_SETSIZE, &set, 0, 0, 0) < 0) {
     51 	    msg ("Service %s: interrupt while waiting for activity: %d (%s)",
     52 		 activeservice->name, errno, strerror(errno));
     53 	    continue;
     54 	}
     55 
     56 	/* Accept the client-side connection. */
     57 	size = sizeof(clientname);
     58 	if ( (new = accept (server_sock, (struct sockaddr *) &clientname,
     59 			    (socklen_t *) &size)) < 0 )
     60 	    error ("Service %s: failure while accepting on server socket: %s",
     61 		   activeservice->name, strerror(errno));
     62 
     63 	/* Store client IP, it's used for lots of logging. */
     64 	client_ip = inet_ntoa (clientname.sin_addr);
     65 	msg ("Service %s: connection from %s, socket %d", 
     66 	     activeservice->name, client_ip, new);
     67 	if (ipf_denied ()) {
     68 	    warning ("Service %s: %s matches deny list, "
     69 		     "terminating connection", activeservice->name, client_ip);
     70 	    close (new);
     71 	    continue;
     72 	}
     73 	if (!ipf_allowed ()) {
     74 	    warning ("Service %s: %s failes to match allow list, "
     75 		     "terminating connection", activeservice->name, client_ip);
     76 	    close (new);
     77 	    continue;
     78 	}
     79 
     80 	/* Backend yet to be defined. */
     81 	current_backend = -1;
     82 
     83 	/* Incase of a http type service: handle separately. */
     84 	if (activeservice->type == type_http) {
     85 	    http_serve (new);
     86 	    close (new);
     87 	    continue;
     88 	}
     89 	
     90 	/* This is an 'any' service type.
     91 	 * Leave it alone if there are no back ends or if we exceed
     92 	 * the max allowed clients. IN THAT CASE WE RETURN so that
     93 	 * runservice() may close the listener socket, sleep, and
     94 	 * create a new one.
     95 	 */
     96 	if (! backend_count()) {
     97 	    warning ("Service %s: no back ends available",
     98 		     activeservice->name);
     99 	    close (new);
    100 	    return;
    101 	}
    102 
    103 	/* Retry back ends until we succeed. */
    104 	backend_selected = 0;
    105 	while (!backend_selected) {
    106 	    msg ("Service %s: About to choose a back end",
    107 		 activeservice->name);
    108 	    choose_backend();
    109 	    if (current_backend < 0) {
    110 		/* No back ends available now. NOTE: we return so that
    111 		 * runservice() will retry in some time. */
    112 		close (new);
    113 		return;
    114 	    }
    115 	    
    116 	    /* Connect to the backend. If this fails then we'll sleep
    117 	     * and re-enter the backend selection loop instead of returning.
    118 	     * In the loop we may need to decide to return after all. */
    119 	    msg ("Service %s: trying back end %s, port %d",
    120 		 activeservice->name, 
    121 		 activeservice->backend[current_backend].server,
    122 		 activeservice->backend[current_backend].port);
    123 	    if ( (backend_sock = backend_connect()) < 0 ) {
    124 		warning ("Service %s: failed to connect to server %s:%d "
    125 			 "(ret %d)", activeservice->name,
    126 			 activeservice->backend[current_backend].server,
    127 			 activeservice->backend[current_backend].port,
    128 			 backend_sock);
    129 		continue;
    130 	    }
    131 
    132 	    /* Got a live one! */
    133 	    backend_selected++;
    134 	    if (fork_tcp_servicer (current_backend)) {
    135 		/* We're the parent branch here. Close sockets so that
    136 		 * we don't run out of file descriptors, and loop into
    137 		 * the next select/accept run. */
    138 		close (new);
    139 		close (backend_sock);
    140 	    } else {
    141 		/* Child branch: piggyback to and fro.
    142 		 * This one never returns. */
    143 		incr_client_count();
    144 		log_activity_start ();
    145 		flag_verbose =
    146 		    activeservice->backend[current_backend].verbosity;
    147 		copysockets (new, backend_sock);
    148 	    }
    149 	}
    150     }
    151 }