Example #1
0
int
main (int ac, char *av[])
{
    int ret, ch;
    char *logfile = NULL;
    int i, ok;
    char *tmp, *ptr;
    uv_signal_t *sigint;
    uv_signal_t *sigterm;
    char *pidfile = NULL;

    struct destination *destination = NULL;
    struct listener *listener;

    struct rlimit rl;
    rl.rlim_cur = 65535;
    rl.rlim_max = 65535;

    setrlimit (RLIMIT_NOFILE, &rl);

    rl.rlim_cur = RLIM_INFINITY;
    rl.rlim_max = RLIM_INFINITY;

    setrlimit (RLIMIT_CORE, &rl);

    signal (SIGPIPE, SIG_IGN);

    char *mysqltype = NULL;

    setenv ("TZ", ":/etc/localtime", 0);
    tzset ();

    memset (logstring, '\0', sizeof (logstring));
    for (i = 0; i < ac; i++) {
        if (strlen (logstring) + strlen (av[i]) >= sizeof (logstring)) {
            break;
        }
        strcat (logstring, av[i]);

        if (i != ac - 1) {
            strcat (logstring, " ");
        }
    }

    pool = malloc (sizeof (*pool));

    bufpool_init (pool, BUF_SIZE);

/*
    uv_timer_t *handle;
    handle = malloc (sizeof(uv_timer_t));
    uv_timer_init(uv_default_loop(),handle);
    uv_timer_start(handle, bufpool_print_stats, 1000, 1000);
*/


    sigint = malloc (sizeof (uv_signal_t));
    sigterm = malloc (sizeof (uv_signal_t));
    uv_signal_init (uv_default_loop (), sigint);
    uv_signal_init (uv_default_loop (), sigterm);
    uv_signal_start (sigint, signal_handler, SIGINT);
    uv_signal_start (sigterm, signal_handler, SIGTERM);

    openlog ("rum", LOG_NDELAY | LOG_PID, LOG_DAEMON);

    if (ac == 1) {
        usage ();
    }

    /* destination is global variable a pointer to struct destination
     * struct destination forms a linked list
     * first_destination is pointer to first struct
     * 
     * struct listener is the same
     */

    listener = NULL;

    int option_index = 0;
    static struct option long_options[] = {
        {"background", no_argument, 0, 'b'},
        {"destination", required_argument, 0, 'd'},
        {"source", required_argument, 0, 's'},
        {"stats", required_argument, 0, 'm'},
        {"logfile", required_argument, 0, 'l'},
        {"mysql-cdb", required_argument, 0, 'M'},
        {"postgresql-cdb", required_argument, 0, 'P'},
        {"mysqltype", required_argument, 0, 't'},
        {"failover-r", required_argument, 0, 'R'},
        {"failover", required_argument, 0, 'f'},
        {"read-timeout", required_argument, 0, 0},
        {"connect-timeout", required_argument, 0, 0},
        {"pidfile", required_argument, 0, 'p'},
        {"loglogins", no_argument, 0, 'L'},
        {0, 0, 0, 0}
    };


    while ((ch =
            getopt_long (ac, av, "bd:s:m:l:M:P:t:r:f:R:p:L", long_options,
                         &option_index)) != -1) {
        switch (ch) {
        case 0:
            if (strcmp (long_options[option_index].name, "read-timeout") == 0)
                read_timeout = atoi (optarg);
            if (strcmp (long_options[option_index].name, "connect-timeout") ==
                0)
                connect_timeout = atoi (optarg);

            break;

        case 'b':
            daemonize = 1;
            break;
        case 's':
        case 'm':
            if (listener == NULL) {
                first_listener = listener = malloc (sizeof (struct listener));
            } else {
                listener->next = malloc (sizeof (struct listener));
                listener = listener->next;
            }
            listener->s = strdup (optarg);
            listener->stream = NULL;
            listener->next = NULL;
            /* vynulujeme statistiky */
            listener->nr_conn = 0;
            listener->nr_allconn = 0;
            listener->input_bytes = 0;
            listener->output_bytes = 0;
            if (ch == 's') {
                listener->type = LISTENER_DEFAULT;
            } else if (ch == 'm') {
                listener->type = LISTENER_STATS;
            }
            break;
        case 'M':
            /* enable mysql module */
            mysql_cdb_file = strdup (optarg);
            break;
        case 'P':
            /* enable mysql module */
            postgresql_cdb_file = strdup (optarg);
            break;

        case 'd':
            first_destination = destination =
                malloc (sizeof (struct destination));
            prepare_upstream (optarg, destination);
            break;
        case 'l':
            logfile = strdup (optarg);
            break;
        case 'L':
            loglogins = 1;
            break;
        case 't':
            mysqltype = optarg;
            break;
        case 'f':
            mode = MODE_FAILOVER;
            ptr = tmp = strdup (optarg);
            i = 0;
            while (tmp[i] != '\0') {
                if (tmp[i] == ',') {
                    tmp[i] = '\0';
                    add_destination (ptr);
                    destinations++;
                    ptr = tmp + i + 1;
                }
                i++;
            }

            add_destination (ptr);
            destinations++;

            break;

        case 'R':
            mode = MODE_FAILOVER_R;
            ptr = tmp = strdup (optarg);
            i = 0;
            while (tmp[i] != '\0') {
                if (tmp[i] == ',') {
                    tmp[i] = '\0';
                    add_destination (ptr);
                    destinations++;
                    ptr = tmp + i + 1;
                }
                i++;
            }

            add_destination (ptr);
            destinations++;
            randomize_destinations ();

            break;

        case 'p':
            pidfile = strdup (optarg);
            break;

        }
    }

    /* if mysql module is enabled, open cdb file and create EV_SIGNAL event which call repoen_cdb().
     * if someone send SIGUSR1 cdb file is reopened, but this is automatically triggered by timeout with
     * CDB_RELOAD_TIME seconds (default 2s)
     *
     * reopen_cdb is called from main event loop, it is not called directly by signal,
     * so it is race condition free (safe to free and init global cdb variable)
     */
    if (mysql_cdb_file) {
        init_mysql_cdb_file (mysqltype);
    }

    if (postgresql_cdb_file) {
        init_postgresql_cdb_file (mysqltype);
    }


    if (daemonize) {
        if (logfile) {
            if (daemon (0, 1) < 0) {
                perror ("daemon()");
                exit (0);
            }
            close (0);
            close (1);
            close (2);
            ret =
                open (logfile, O_WRONLY | O_CREAT | O_APPEND,
                      S_IRUSR | S_IWUSR);
            if (ret != -1) {
                dup2 (ret, 1);
                dup2 (ret, 2);
            }
        } else {
            if (daemon (0, 0) < 0) {
                perror ("daemon()");
                exit (0);
            }
        }
    }

    /* add all listen (-s -m) ports to event_base, if someone connect: accept_connect is executed with struct listener argument */
    for (listener = first_listener; listener; listener = listener->next) {
        for (i = 0, ok = 0; i < 10; i++) {
            listener->stream = create_listen_socket (listener->s);
            listener->stream->data = listener;
            int r =
                uv_listen ((uv_stream_t *) listener->stream, -1,
                           on_incoming_connection);

            if (r) {
                logmsg ("listen to %s failed, retrying", listener->s);
                uv_close ((uv_handle_t *) listener->stream, on_close_listener);
                usleep (200 * 1000);
            } else {
                logmsg ("listening on %s", listener->s);
                ok = 1;
                break;
            }
        }

        if (ok == 0) {
            logmsg ("listen to %s failed, exiting", listener->s);
            _exit (-1);
        }

    }

    if (!first_destination && !mysql_cdb_file && !postgresql_cdb_file) {
        usage ();
    }

    if (daemonize) {
        if (pidfile) {
            FILE *fp = fopen(pidfile, "w");
            if (fp) {
                fprintf (fp, "%d", getpid());
                fclose (fp);
            } else {
                logmsg("cannot open pidfile %s (%s)", pidfile, strerror (errno));
            }
        }
    }

    /* main libuv loop */
    uv_run (uv_default_loop (), UV_RUN_DEFAULT);

    /* SIGINT || SIGTERM received, clean up */
    bufpool_done (pool);
    free (pool);

    if (mysql_cdb_file) {
        free (mysql_cdb_file);
    }

    if (postgresql_cdb_file) {
        free (postgresql_cdb_file);
    }


    struct destination *dst;
    dst = first_destination;
    while (dst) {
        destination = dst->next;
        free (dst->s);
        free (dst);
        dst = destination;
    }

    free (sigint);
    free (sigterm);

    exit (0);
}
Example #2
0
File: rum.c Project: Apploud/rum
int main (int ac, char *av[]) {
	int ret,ch,daemonize=0;
	char *logfile=NULL;
	
	struct destination *destination;
	struct listener *listener;

	signal(SIGPIPE ,SIG_IGN);

	if (ac==1) {
		usage();
	}

	/* destination is global variable a pointer to struct destination
	 * struct destination forms a linked list
	 * first_destination is pointer to first struct
	 * 
	 * struct listener is the same
	 */
	first_destination=destination=malloc(sizeof(struct destination));

	listener=NULL;

	while ((ch = getopt(ac, av, "bd:s:m:l:M:")) != -1) {
		switch (ch) {
			case 'b':
				daemonize=1;
			break;
			case 's':
			case 'm':
				if (listener==NULL) {
					first_listener = listener = malloc(sizeof(struct listener));
				} else {
					listener->next = malloc(sizeof(struct listener));
					listener = listener->next;
				}
				listener->s=strdup(optarg);
				listener->fd=create_listen_socket(optarg);
				listener->next=NULL;
				/* vynulujeme statistiky */
				listener->nr_conn=0;
				listener->nr_allconn=0;
				listener->input_bytes=0;
				listener->output_bytes=0;
				if (ch=='s') {
					listener->type=LISTENER_DEFAULT;
				} else if (ch=='m') {
					listener->type=LISTENER_STATS;
				}
			break;
			case 'M':
				/* enable mysql module */
				mysql_cdb_file=strdup(optarg);
			break;
			case 'd':
				prepareclient(optarg, destination);
			break;
			case 'l':
				logfile=strdup(optarg);
			break;
		}
	}

	event_base=event_base_new();

	/* if mysql module is enabled, open cdb file and create EV_SIGNAL event which call repoen_cdb().
	 * if someone send SIGUSR1 cdb file is reopened, but this is automatically triggered by timeout with
	 * CDB_RELOAD_TIME seconds (default 2s)
	 *
	 * reopen_cdb is called from main event loop, it is not called directly by signal,
	 * so it is race condition free (safe to free and init global cdb variable)
	 */
	if (mysql_cdb_file) {
		init_mysql_cdb_file();
	}

	if (daemonize) {
		if (logfile) {
			if (daemon(0,1)<0) {
				perror("daemon()");
				exit(0);
			}
			close(0);
			close(1);
			close(2);
			ret=open(logfile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
			if (ret!=-1) {
				dup2(ret,1);
				dup2(ret,2);
			}
		} else {
			if (daemon(0,0)<0) {
				perror("daemon()");
				exit(0);
			}
		}
	}

	/* add all listen (-s -m) ports to event_base, if someone connect: accept_connect is executed with struct listener argument */
	for (listener=first_listener; listener; listener=listener->next) {
		struct event *ev;

		ev=event_new(event_base, listener->fd, EV_READ|EV_PERSIST, accept_connect, listener);
		event_add(ev,NULL);
	}

	/* main libevent loop */
	event_base_loop(event_base,0);

	usage();

	exit(0);
}