Esempio n. 1
0
static int signal_pipe_dispatch(void) {
    int sig, err;

    s_log(LOG_DEBUG, "Dispatching signals from the signal pipe");
    while(readsocket(signal_pipe[0], (char *)&sig, sizeof sig)==sizeof sig) {
        switch(sig) {
#ifndef USE_WIN32
        case SIGCHLD:
            s_log(LOG_DEBUG, "Processing SIGCHLD");
#ifdef USE_FORK
            client_status(); /* report status of client process */
#else /* USE_UCONTEXT || USE_PTHREAD */
            child_status();  /* report status of libwrap or 'exec' process */
#endif /* defined USE_FORK */
            break;
#endif /* !defind USE_WIN32 */
        case SIGNAL_RELOAD_CONFIG:
            s_log(LOG_DEBUG, "Processing SIGNAL_RELOAD_CONFIG");
            err=parse_conf(NULL, CONF_RELOAD);
            if(err) {
                s_log(LOG_ERR, "Failed to reload the configuration file");
            } else {
                unbind_ports();
                log_close();
                apply_conf();
                log_open();
                if(bind_ports()) {
                    /* FIXME: handle the error */
                }
            }
            break;
        case SIGNAL_REOPEN_LOG:
            s_log(LOG_DEBUG, "Processing SIGNAL_REOPEN_LOG");
            log_close();
            log_open();
            s_log(LOG_NOTICE, "Log file reopened");
            break;
        case SIGNAL_TERMINATE:
            s_log(LOG_DEBUG, "Processing SIGNAL_TERMINATE");
            s_log(LOG_NOTICE, "Terminated");
            return 2;
        default:
            s_log(LOG_ERR, "Received signal %d; terminating", sig);
            return 1;
        }
    }
    s_log(LOG_DEBUG, "Signal pipe is empty");
    return 0;
}
Esempio n. 2
0
void client_stop (client_t *c)
{
    int i;

    if (c->sock == MAX_SOCK_NUM)
        return;

    // attempt to close the connection gracefully (send a FIN to other side)
    socket_disconnect (c->sock);

    // wait a second for the connection to close
    for (i=0; i<100; i++) {
        if (client_status (c) == SnSR_CLOSED)
            break;
        usleep (10000);
    }

    // if it hasn't closed, close it forcefully
    if (client_status(c) != SnSR_CLOSED)
        socket_close (c->sock);

    _socket_port[c->sock] = 0;
    c->sock = MAX_SOCK_NUM;
}
Esempio n. 3
0
void server_accept()
{
    unsigned sock;
    client_t client;
    int listening = 0;

    for (sock = 0; sock < MAX_SOCK_NUM; sock++) {
        client_init_sock (&client, sock);

        if (_socket_port[sock] == _server_port) {
            if (client_status (&client) == SnSR_LISTEN) {
                listening = 1;
            }
            else if (client_status (&client) == SnSR_CLOSE_WAIT &&
                     ! client_available (&client)) {
                client_stop (&client);
            }
        }
    }

    if (! listening) {
        server_init (_server_port);
    }
}
Esempio n. 4
0
void server_write (const uint8_t *buffer, size_t size)
{
    unsigned sock;
    client_t client;

    server_accept();

    for (sock = 0; sock < MAX_SOCK_NUM; sock++) {
        client_init_sock (&client, sock);

        if (_socket_port[sock] == _server_port &&
          client_status (&client) == SnSR_ESTABLISHED) {
            client_write (&client, buffer, size);
        }
    }
}
Esempio n. 5
0
void server_init (unsigned port)
{
    unsigned sock;
    client_t client;

    _server_port = port;
    for (sock = 0; sock < MAX_SOCK_NUM; sock++) {
        client_init_sock (&client, sock);

        if (client_status (&client) == SnSR_CLOSED) {
            socket_init (sock, SnMR_TCP, port, 0);
            socket_listen (sock);
            _socket_port[sock] = port;
            break;
        }
    }
}
Esempio n. 6
0
File: read.c Progetto: lavabit/magma
/**
 * @brief	Read data from a network connection, and store the data in the connection context buffer.
 * @return	-1 on general failure, -2 if the connection was reset, or the amount of data that was read.
 */
int64_t client_read(client_t *client) {

	int_t counter = 0;
	ssize_t bytes = 0;
	bool_t blocking = true;
	stringer_t *error = NULL;

#ifdef MAGMA_PEDANTIC
	int_t local = 0;
	stringer_t *ip = NULL, *cipher = NULL;
#endif

	if (!client || client->sockd == -1 || client_status(client) < 0) {
		return -1;
	}

	// Check for data past the current line buffer.
	else if (pl_length_get(client->line) && st_length_get(client->buffer) > pl_length_get(client->line)) {

		// Move the unused data to the front of the buffer.
		mm_move(st_data_get(client->buffer), st_data_get(client->buffer) + pl_length_get(client->line), st_length_get(client->buffer) - pl_length_get(client->line));

		// Update the length.
		st_length_set(client->buffer, st_length_get(client->buffer) - pl_length_get(client->line));

		// Clear the line buffer.
		client->line = pl_null();
	}
	// Otherwise reset the buffer and line lengths to zero.
	else {
		st_length_set(client->buffer, 0);
		client->line = pl_null();
	}

	// Loop until the buffer has data or we get an error.
	do {
		blocking = st_length_get(client->buffer) ? false : true;

		// Read bytes off the network. If data is already in the buffer this should be a non-blocking read operation so we can
		// return the already buffered data without delay.
		if (client->tls) {

			// If bytes is zero or below and the library isn't asking for another read, then an error occurred.
			bytes = tls_read(client->tls, st_char_get(client->buffer) + st_length_get(client->buffer),
				st_avail_get(client->buffer) - st_length_get(client->buffer), blocking);

			// If zero bytes were read, or a negative value was returned to indicate an error, call tls_erorr(), which will return
			// NULL if the error can be safely ignored. Otherwise log the output for debug purposes.
			if (bytes <= 0 && (error = tls_error(client->tls, bytes, MANAGEDBUF(512)))) {
#ifdef MAGMA_PEDANTIC
				cipher = tls_cipher(client->tls, MANAGEDBUF(128));
				ip = ip_presentation(client->ip, MANAGEDBUF(INET6_ADDRSTRLEN));

				log_pedantic("TLS client read operation failed. { ip = %.*s / %.*s / result = %zi%s%.*s }",
					st_length_int(ip), st_char_get(ip), st_length_int(cipher), st_char_get(cipher),
					bytes, (error ? " / " : ""), st_length_int(error), st_char_get(error));
#endif
				client->status = -1;
				return -1;
			}
			// This will occur when the read operation results in a 0, or negative value, but TLS error returns NULL to
			// indicate it was a transient error. For transient errors we simply set bytes equal to 0 so the read call gets retried.
			else if (bytes <= 0) {
				bytes = 0;
			}
		}
		else {

			errno = 0;

			bytes = recv(client->sockd, st_char_get(client->buffer) + st_length_get(client->buffer),
				st_avail_get(client->buffer) - st_length_get(client->buffer), (blocking ? 0 : MSG_DONTWAIT));

			// Check for errors on non-SSL reads in the traditional way.
			if (bytes <= 0 && tcp_status(client->sockd)) {
#ifdef MAGMA_PEDANTIC
				local = errno;
				ip = ip_presentation(client->ip, MANAGEDBUF(INET6_ADDRSTRLEN));

				log_pedantic("TCP client read operation failed. { ip = %.*s / result = %zi / error = %i / message = %s }",
					st_length_int(ip), st_char_get(ip), bytes, local, strerror_r(local, MEMORYBUF(1024), 1024));
#endif
				client->status = -1;
				return -1;
			}

		}

		// We actually read in data, so we need to update the buffer to reflect the amount of data it currently holds.
		if (bytes > 0) {
			st_length_set(client->buffer, st_length_get(client->buffer) + bytes);
		}

	} while (blocking && counter++ < 128 && !st_length_get(client->buffer) && status());

	// If there is data in the buffer process it. Otherwise if the buffer is empty and the connection appears to be closed
	// (as indicated by a return value of 0), then return -1 to let the caller know the connection is dead.
	if (st_length_get(client->buffer)) {
		client->status = 1;
	}
	else if (!bytes) {
		client->status = 2;
		return -2;
	}

	return st_length_get(client->buffer);
}
Esempio n. 7
0
NOEXPORT int signal_pipe_dispatch(void) {
    static int sig;
    static size_t ptr=0;
    ssize_t num;
    char *sig_name;

    s_log(LOG_DEBUG, "Dispatching signals from the signal pipe");
    for(;;) {
        num=readsocket(signal_pipe[0], (char *)&sig+ptr, sizeof sig-ptr);
        if(num==-1 && get_last_socket_error()==S_EWOULDBLOCK) {
            s_log(LOG_DEBUG, "Signal pipe is empty");
            return 0;
        }
        if(num==-1 || num==0) {
            if(num)
                sockerror("signal pipe read");
            else
                s_log(LOG_ERR, "Signal pipe closed");
            s_poll_remove(fds, signal_pipe[0]);
            closesocket(signal_pipe[0]);
            closesocket(signal_pipe[1]);
            if(signal_pipe_init()) {
                s_log(LOG_ERR,
                    "Signal pipe reinitialization failed; terminating");
                return 1;
            }
            s_poll_add(fds, signal_pipe[0], 1, 0);
            s_log(LOG_ERR, "Signal pipe reinitialized");
            return 0;
        }
        ptr+=(size_t)num;
        if(ptr<sizeof sig) {
            s_log(LOG_DEBUG, "Incomplete signal pipe read (ptr=%ld)",
                (long)ptr);
            return 0;
        }
        ptr=0;
        switch(sig) {
#ifndef USE_WIN32
        case SIGCHLD:
            s_log(LOG_DEBUG, "Processing SIGCHLD");
#ifdef USE_FORK
            client_status(); /* report status of client process */
#else /* USE_UCONTEXT || USE_PTHREAD */
            child_status();  /* report status of libwrap or 'exec' process */
#endif /* defined USE_FORK */
            break;
#endif /* !defind USE_WIN32 */
        case SIGNAL_RELOAD_CONFIG:
            s_log(LOG_DEBUG, "Processing SIGNAL_RELOAD_CONFIG");
            if(options_parse(CONF_RELOAD)) {
                s_log(LOG_ERR, "Failed to reload the configuration file");
            } else {
                unbind_ports();
                log_close();
                options_apply();
                log_open();
                ui_config_reloaded();
                if(bind_ports()) {
                    /* FIXME: handle the error */
                }
            }
            break;
        case SIGNAL_REOPEN_LOG:
            s_log(LOG_DEBUG, "Processing SIGNAL_REOPEN_LOG");
            log_close();
            log_open();
            s_log(LOG_NOTICE, "Log file reopened");
            break;
        case SIGNAL_TERMINATE:
            s_log(LOG_DEBUG, "Processing SIGNAL_TERMINATE");
            s_log(LOG_NOTICE, "Terminated");
            return 1;
        default:
            sig_name=signal_name(sig);
            s_log(LOG_ERR, "Received %s; terminating", sig_name);
            str_free(sig_name);
            return 1;
        }
    }
}