Пример #1
0
// Function called by network thread, used to separate the TCP listener from the console thread
void *tcp_listen()
{
	// Set up p2p_t struct, to pass variables into the thread function
	p2p_t params;

	// Create output buffer, in case the base server must communicate directly to the client
	char out[512] = { '\0' };

	// Loop infinitely until Ctrl+C SIGINT is caught by the signal handler
   	while(1)
	{
		// Attempt to accept incoming connections using the incoming socket
		if((inc_fd = accept(loc_fd, (struct sockaddr *)&inc_addr, &inc_len)) == -1)
		{
			// Print an error message and quit if server cannot accept connections
			fprintf(stderr, "%s: %s failed to accept incoming connections\n", SERVER_NAME, ERROR_MSG);
			return (void *)-1;
		}
		else
		{
			// If a connection is accepted, continue routines.
			// Capture client's IP address for logging.
			inet_ntop(inc_addr.ss_family, get_in_addr((struct sockaddr *)&inc_addr), clientaddr, sizeof(clientaddr));

			// Print message when connection is received, and increment client counter
			fprintf(stdout, "%s: %s client connected from %s [fd: %d] [users: %d/%d]\n", SERVER_NAME, OK_MSG, clientaddr, inc_fd, client_count(1), num_threads);

			// If client count reaches the utilization threshold, print a warning
			if(((double)client_count(0) >= ((double)num_threads * TP_UTIL)) && (client_count(0) <= num_threads))
			{
				// Print warning to server console, alter wording slightly if utilization is maxed out
				if(client_count(0) == num_threads)
					fprintf(stdout, "%s: %s thread pool exhausted [users: %d/%d]\n", SERVER_NAME, WARN_MSG, client_count(0), num_threads);
				else
					fprintf(stdout, "%s: %s thread pool nearing exhaustion [users: %d/%d]\n", SERVER_NAME, WARN_MSG, client_count(0), num_threads);
			}
			// If client count exceeds the number of threads in the pool, print an error
			else if((client_count(0)) > num_threads)
			{
				// Print error to console
				fprintf(stderr, "%s: %s thread pool over-exhausted [users: %d/%d]\n", SERVER_NAME, ERROR_MSG, client_count(0), num_threads);

				// Generate message to send to client
				sprintf(out, "%s: %s server has currently reached maximum user capacity, please wait\n", SERVER_NAME, USER_MSG);
				send_msg(inc_fd, out);
			}

			// Store user's file descriptor and IP address in the params struct
			params.fd = inc_fd;
			strcpy(params.ipaddr, clientaddr);

			// On client connection, add work to the threadpool, pass in params struct
			thpool_add_work(threadpool, &p2p, (void*)&params);
		}
	}
}
Пример #2
0
// this handler fires, and it collates the stats collected, and possibly outputs to the log.
// If we have migrating stats, then we need to migrate to the next slot.
static void stats_handler(int fd, short int flags, void *arg)
{
	int changed = 0;
	int new_nodes;
	int new_clients;
	
	assert(fd == -1);
	assert(flags & EV_TIMEOUT);
	assert(arg == NULL);

	new_nodes = node_active_count();
	if (_stats.last.active_nodes != new_nodes) {
		_stats.last.active_nodes = new_nodes;
		changed++;
	}
	
	new_clients = client_count();
	if (_stats.last.clients != new_clients) {
		_stats.last.clients = new_clients;
		changed++;
	}
	
	if (_stats.bytes_in > 0 || _stats.bytes_out > 0) {
		changed ++;
	}
	
	if (changed > 0) {
		logger(LOG_STATS, "Stats. Nodes:%d, Clients:%d, Bytes IN:%d, Bytes OUT:%d", new_nodes, new_clients, _stats.bytes_in, _stats.bytes_out);
	}

	_stats.bytes_in = 0;
	_stats.bytes_out = 0;

	evtimer_add(_stats_event, &_timeout_stats);
}
Пример #3
0
// Simple dummy application which runs on the thread pool, receiving input and echoing it back
void *echo(void *arg)
{
	// Create and clear input and output buffers
	char in[512], out[512] = { '\0' };

	// Keep track of user's file descriptor as passed in by thread arguments
	int user_fd = *(int *)arg;

	// Send user initial welcome message
	sprintf(out, "%s: %s type a message, or /quit to quit\n", APP_NAME, USER_MSG);
	send_msg(user_fd, out);

	// Loop until the user sends in the quit command
	while (strncmp(in, "/quit", 5) != 0)
	{
		// Receive user's message, remove newlines
		recv_msg(user_fd, (char *)&in);
		if (in[strlen(in) - 1] == '\n' || in[strlen(in) - 1] == '\r')
		{
			in[strlen(in) - 1] = '\0';
		}

		// Echo it back to the user
		sprintf(out, "%s: %s received: %s\n", APP_NAME, USER_MSG, in);
		send_msg(user_fd, out);
	}

	// Send user goodbye message
	sprintf(out, "%s: %s goodbye!\n", APP_NAME, USER_MSG);
	send_msg(user_fd, out);

	// Clear I/O buffers
	memset(&in, 0, sizeof(in));
	memset(&out, 0, sizeof(out));

	// Decrement client count
	client_count(-1);

	// Print user disconnect message to console
	fprintf(stdout, "%s: %s client disconnected [fd: %d]\n", APP_NAME, OK_MSG, user_fd);

	// Attempt to close user socket
	if (close(user_fd) == -1)
	{
		// On failure, print error to console
		fprintf(stderr, "%s: %s failed to close user socket\n", APP_NAME, ERROR_MSG);
		return (void *)-1;
	}

	// If all routines succeded, return success, so that thread may rejoin the pool
	return (void *)0;
}
Пример #4
0
static void
start_server (void) {
    int                 client_sd;
    int                 daemon_sd;
    int                 connected_sd;
    struct sockaddr_in  client_sa;
    struct sockaddr_in  daemon_sa;
    struct sockaddr_in  connected_sa;
    socklen_t           size;
    fd_set              socket_set;
    int                 nfds;
    struct ifreq        if_info;
    struct sockaddr_in  *if_addr;
    char                addr[INET_ADDRSTRLEN];
    struct client       *c;
    struct daemon       *d;
    struct parsed_cmd   *pcmd = NULL;
    char                *ident_msg;
    int                 port;
    char                *colon;


    /* Prepare all the threads */
    slow_pool = NULL;
    fast_pool = NULL;
    clients_pool = NULL;
    daemons_pool = NULL;

    ABORT_IF (!(slow_pool = pool_create (prefs->nb_proc)),
        "Unable to create slow_pool")

    ABORT_IF (!(fast_pool = pool_create (prefs->nb_proc)),
        "Unable to create fast_pool")

    ABORT_IF (!(clients_pool = pool_create (prefs->max_clients)),
        "Unable to create clients_pool")

    ABORT_IF (!(daemons_pool = pool_create (prefs->max_daemons)),
        "Unable to create daemons_pool")

    /* Create the shared directory if it does not exist already */
    ABORT_IF (create_dir (prefs->shared_folder, (mode_t)0755) < 0,
                "Unable to create shared directory")

    /* Initialize global pointers and their semaphores */
    clients = NULL;
    ABORT_IF (sem_init (&clients_lock, 0, 1) < 0,
        "Unable to sem_init clients_lock")

    daemons = NULL;
    ABORT_IF (sem_init (&daemons_lock, 0, 1) < 0,
        "Unable to sem_init daemons_lock")

    file_cache = NULL;
    ABORT_IF (sem_init (&file_cache_lock, 0, 1) < 0,
        "Unable to sem_init file_cache_lock")

    list_client = NULL;
    ABORT_IF (sem_init (&list_lock, 0, 1) < 0,
        "Unable to sem_init list_lock")

    downloads = NULL;
    ABORT_IF (sem_init (&downloads_lock, 0, 1) < 0,
        "Unable to sem_init download_queue_lock")

    client_sa.sin_family        = AF_INET;
    client_sa.sin_addr.s_addr   = INADDR_ANY;
    client_sa.sin_port          = htons (prefs->client_port);
    client_sd = socket_init (&client_sa);
    ABORT_IF (client_sd < 0,
        "Unable to socket_init client_sd")

    daemon_sa.sin_family        = AF_INET;
    daemon_sa.sin_addr.s_addr   = INADDR_ANY;
    daemon_sa.sin_port          = htons (prefs->daemon_port);
    daemon_sd = socket_init (&daemon_sa);
    ABORT_IF (daemon_sd < 0,
        "Unable to socket_init daemon_sd")

#if 1
    /* We get our ip */
    memcpy (if_info.ifr_name, prefs->interface, strlen (prefs->interface) + 1);
    if (ioctl (daemon_sd, SIOCGIFADDR, &if_info) == -1) {
        log_failure (log_file, "Can't get my ip from interface");
        log_failure (log_file, "LOL ERRNO : %s\n", strerror (errno));
        goto abort;
    }
    if_addr = (struct sockaddr_in *)&if_info.ifr_addr;
    inet_ntop (AF_INET, &if_addr->sin_addr, my_ip, INET_ADDRSTRLEN);
    log_success (log_file, "Found my IP : %s", my_ip);
#endif

    /* socket_set contains both client_sd and daemon_sd */
    FD_ZERO (&socket_set);
    size = sizeof (connected_sa);
    nfds = NFDS (client_sd, daemon_sd);
    for (;;) {
        /*
         * It is VERY important to FD_SET at each loop, because select
         * will FD_UNSET the socket descriptors
         */
        FD_SET (client_sd, &socket_set);
        FD_SET (daemon_sd, &socket_set);

        /* Block until a socket is ready to accept */
        if (select (nfds, &socket_set, NULL, NULL, NULL) < 0) {
            log_failure (log_file, "main () : select failed");
        }

        if (FD_ISSET (client_sd, &socket_set)) {
            if ((connected_sd = (accept (client_sd,
                                        (struct sockaddr *) &connected_sa,
                                        &size))) < 0) {
                log_failure (log_file, "Failed to accept incoming connection.");
                break;
            }

            /* Can we handle this client? */
            if (client_count () > prefs->max_clients) {
                socket_sendline (connected_sd, " < Too many clients\n");
                goto close_socket;
            }

            /* Then, let's handle him */
            if (!inet_ntop (AF_INET, &connected_sa.sin_addr,
                            addr, INET_ADDRSTRLEN)) {
                socket_sendline (connected_sd, " < Oops\n");
                goto close_socket;
            }
            if (!(c = client_new (connected_sd, addr))) {
                socket_sendline (connected_sd, " < Sorry pal :(\n");
            }

            pool_queue (clients_pool, handle_client, c);
        }
        else if (FD_ISSET (daemon_sd, &socket_set)) {
            if ((connected_sd = (accept (daemon_sd,
                                        (struct sockaddr *) &connected_sa,
                                        &size))) < 0) {
                log_failure (log_file, "Failed to accept incoming connection.");
                break;
            }

            /* Can we handle this daemon? */
            if (daemon_count () > prefs->max_daemons) {
                socket_sendline (connected_sd, " < Too many daemons\n");
                goto close_socket;
            }

            /* Let's identify him first */
            ident_msg = socket_try_getline (connected_sd,
                                            IDENTIFICATION_TIMEOUT);
            if (!ident_msg) {
                socket_sendline (connected_sd,
                                "error: identification timed out\n");
                goto close_socket;
            }
            if (cmd_parse_failed ((pcmd = cmd_parse (ident_msg, NULL)))) {
                pcmd = NULL;
                goto close_socket;
            }
            if (pcmd->argc < 2)
                goto close_socket;
            if (strcmp (pcmd->argv[0], "neighbour") != 0)
                goto close_socket;
            if (!(colon = strchr (pcmd->argv[1], ':')))
                goto close_socket;
            port = atoi (colon + 1);

            free (ident_msg);
            cmd_parse_free (pcmd);
            pcmd = NULL;

            if (!inet_ntop (AF_INET, &connected_sa.sin_addr,
                            addr, INET_ADDRSTRLEN)) {
                socket_sendline (connected_sd, " < Oops\n");
                goto close_socket;
            }

            /* Now we've got his port, let him go in */
            if (!(d = daemon_new (connected_sd, addr, port))) {
                socket_sendline (connected_sd, " < Sorry pal :(\n");
                goto close_socket;
            }

            pool_queue (daemons_pool, handle_daemon, d);
        }
        else {
            /* This should never happen : neither client nor daemon!? */
            log_failure (log_file, "Unknown connection");
        }

        continue;

close_socket:
        if (pcmd) {
            cmd_parse_free (pcmd);
            pcmd = NULL;
        }
        close (connected_sd);
    }

abort:
    if (slow_pool)
        pool_destroy (slow_pool);
    if (fast_pool)
        pool_destroy (fast_pool);
    if (clients_pool)
        pool_destroy (clients_pool);
    if (daemons_pool)
        pool_destroy (daemons_pool);
    conf_free (prefs);
    exit (EXIT_FAILURE);
}
Пример #5
0
int sound::outputcallback(const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData){
	sound * psound = (sound*)userData;
	short * voiceBuffer = (short *)output;
	memset(voiceBuffer, 0, psound->BUFF_LONG * sizeof(short) * psound->outputStreamParameters.channelCount);

	int empty = 0;
	iterator_client_set([&empty, psound, frameCount, &voiceBuffer](std::map<int, client*> & set){
		for (auto var : set){
			char * outbuf = 0;
			short channelcount = 0;
			int len = 0;
			if (!var.second->read_buff(outbuf, channelcount, len)){
				empty++;
				continue;
			}
			short voicebuf[4096];
			memset(voicebuf, 0, 4096 * sizeof(short));
			psound->_encode.decoded(outbuf, len, (char*)voicebuf, psound->BUFF_LONG * psound->outputStreamParameters.channelCount);

			for (unsigned int i = 0; i < frameCount; i++)
			{
				int src = frameCount - i - 1;
				int dst = src *  psound->outputStreamParameters.channelCount;

				if (voiceBuffer[dst] > 0 && voicebuf[src] > CLAMP_MAX - voiceBuffer[dst]){
					voiceBuffer[dst] = CLAMP_MAX;
				} else if (voiceBuffer[i] <= 0 && voicebuf[src] < CLAMP_MIN - voiceBuffer[dst]){
					voiceBuffer[dst] = CLAMP_MIN;
				} else{
					voiceBuffer[dst] += voicebuf[src];
				}
			}

			for (int channel = 1; channel < psound->outputStreamParameters.channelCount; channel++)
			{
				for (unsigned int i = 0; i < frameCount; i++)
				{
					int src = frameCount - i - 1;// (frameCount - i - 1) * psound->outputStreamParameters.channelCount;
					int dst = src + channel;

					if (voiceBuffer[dst] > 0 && voicebuf[src] > CLAMP_MAX - voiceBuffer[dst]){
						voiceBuffer[dst] = CLAMP_MAX;
					} else if (voiceBuffer[i] <= 0 && voicebuf[src] < CLAMP_MIN - voiceBuffer[dst]){
						voiceBuffer[dst] = CLAMP_MIN;
					} else{
						voiceBuffer[dst] += voicebuf[src];
					}
				}
			}
		}
	});
	if (empty == client_count()){
		return paContinue;
	}

	if (psound->isopenecho == true){
		while (1){
			int _begin = psound->begin.load();
			int _new = _begin + 1;

			if (_new == psound->end.load()){
				break;
			}

			if (_new == 16){
				_new = 0;
			}

			if (psound->begin.compare_exchange_strong(_begin, _new)){
				memcpy(psound->inputbuff[_begin].buf, voiceBuffer, frameCount*psound->outputStreamParameters.channelCount);
				psound->inputbuff[_begin].len = frameCount*psound->outputStreamParameters.channelCount;
				break;
			}
		}
	}
	
	return paContinue;
}
Пример #6
0
// Statistics function, which can be called via console or signal
void print_stats()
{
	// Create variables to calculate elapsed time
	int hours, minutes, seconds;

	// Create a buffer to store total elapsed time
	char runtime[32] = { '\0' };

	// Create a buffer to store thread pool usage calculations
	char tpusage[32] = { '\0' };

	//------------------ CALCULATE RUNTIME ---------------------

	// Calculate total number of seconds since program start
	seconds = (int)difftime(time(NULL), start_time);
	
	// Calculate minutes as the number of seconds divided by 60
	minutes = seconds / 60;

	// Calculate hours as the number of minutes divided by 60
	hours = minutes / 60;

	// Recalculate minutes as the remainder after hours are taken out
	minutes = minutes % 60;

	// Recalculate seconds as the remainder after minutes are taken out
	seconds = seconds % 60;

	// Combine all time information into a single string
	sprintf(runtime, "%02d:%02d:%02d", hours, minutes, seconds);

	//----------------- CALCULATE THREAD POOL USAGE -------------

	// Begin calculating thread pool usage, setting message type accordingly
	// If thread pool is under-capacity...
	if(client_count(0) < (num_threads * TP_UTIL))
	{
		// Set message type to OK
		fprintf(stdout, "%s: %s ", SERVER_NAME, OK_MSG);

		// Format users string as normal
		sprintf(tpusage, "[users: %d/%d]", client_count(0), num_threads);
	}
	// If thread pool is near or at-capacity...
	else if(((double)client_count(0) >= ((double)num_threads * TP_UTIL)) && client_count(0) <= num_threads)
	{
		// Set message type to WARN
		fprintf(stdout, "%s: %s ", SERVER_NAME, WARN_MSG);

		// Format users string with warning color
		sprintf(tpusage, "\033[1;33m[users: %d/%d]\033[0m", client_count(0), num_threads);
	}
	// Finally, if thread pool is over-capacity...
	else
	{
		// Set message type to ERROR
		fprintf(stdout, "%s: %s ", SERVER_NAME, ERROR_MSG);

		// Format users string with error color
		sprintf(tpusage, "\033[1;31m[users: %d/%d]\033[0m", client_count(0), num_threads);
	}
	
	//----------------- PRINT STATISTICS ------------------------

	// Print out server statistics, differ slightly if daemonized
	if(daemonized == 1)
		fprintf(stdout, "daemon running [PID: %d] [time: %s] [lock: %s] [port: %s] [queue: %d] %s\n", getpid(), runtime, lock_location, port, queue_length, tpusage);
	else
		fprintf(stdout, "server running [PID: %d] [time: %s] [port: %s] [queue: %d] %s\n", getpid(), runtime, port, queue_length, tpusage);
}
Пример #7
0
// Shutdown handler, which catches signals and performs shutdown routines to cleanly terminate the server
void shutdown_handler()
{
	// Cancel the network handling thread, stopping all incoming connections
	pthread_cancel(net_thread);

	// If in daemon mode, unlock, close, and remove the lockfile
	if(daemonized == 1)
	{
		// Attempt to unlock lockfile
		if(lockf(pidfile, F_ULOCK, 0) == -1)
		{
			fprintf(stderr, "%s: %s failed to unlock lockfile\n", SERVER_NAME, ERROR_MSG);
			exit(-1);
		}

		// Attempt to close lockfile
		if(close(pidfile) == -1)
		{
			fprintf(stderr, "%s: %s failed to close daemon lockfile\n", SERVER_NAME, ERROR_MSG);
			exit(-1);
		}

		// Attempt to remove lockfile
		if(remove(lock_location) == -1)
		{
			fprintf(stderr, "%s: %s could not remove lockfile %s\n", SERVER_NAME, ERROR_MSG, lock_location);
			exit(-1);
		}
	}

	// Print newline to clean up output
	fprintf(stdout, "\n");

	// Close SQLite database
	if(sqlite3_close(db) != SQLITE_OK)
	{
		// On failure, print error to console and exit
		fprintf(stderr, "%s: %s sqlite: failed to close database\n", SERVER_NAME, ERROR_MSG);
		exit(-1);
	}

        // Attempt to shutdown the local socket
        if(shutdown(loc_fd, 2) == -1)
        {
                // Print error and exit if socket fails to shutdown
                fprintf(stderr, "%s: %s failed to shutdown local socket\n", SERVER_NAME, ERROR_MSG);
                exit(-1);
        }

        // Attempt to close local socket to end program
        if(close(loc_fd) == -1)
        {
                // Print error and exit if socket fails to close
                fprintf(stderr, "%s: %s failed to close local socket\n", SERVER_NAME, ERROR_MSG);
                exit(-1);
        }

	// Destroy created threadpool.  If 0 clients are connected, rejoin the threads.  Else, cancel the threads (force destroy).
	if(client_count(0) == 0)
		thpool_destroy(threadpool, 0);
	else
		thpool_destroy(threadpool, 1);

	// Print final termination message
        fprintf(stdout, "%s: %s kicked %d client(s), server terminated\n", SERVER_NAME, OK_MSG, client_count(0));

        // Exit, returning success
        exit(0);
}