Example #1
0
static void read_conn(struct connection *conn)
{
	int n;

	time(&conn->access);
#ifdef WANT_SSL
	if (conn->ssl) {
		n = openssl_read(conn);
		/* openssl_read can return -EAGAIN if the SSL
		 * connection needs a read or write. */
		if (n == -EAGAIN)
			return;
	} else
#endif
		n = recv(conn->poll->fd, conn->curp, conn->rlen, 0);
	if (n >= 0) {
		if (verbose > 1)
			printf("+ Read %d\n", n);
		conn->endp = conn->curp + n;
		conn->rlen -= n;
		*conn->endp = '\0';

		if (conn->func && conn->func(conn))
			fail_connection(conn);
	} else if (n < 0)
		reset_connection(conn); /* Try again */
}
Example #2
0
/* Close all sockets, free all the socket structs, and send a RST
 * packet to clean up kernel state for each connection.
 * TODO(ncardwell): centralize error handling and ensure test errors
 * always result in a call to these clean-up functions, so we can make
 * sure to reset connections in all cases.
 */
static void close_all_sockets(struct state *state)
{
	struct socket *socket = state->sockets;
	while (socket != NULL)
	{
		if (socket->live.fd >= 0 && !socket->is_closed)
		{
			assert(socket->script.fd >= 0);
			DEBUGP("closing struct state socket "
			       "live.fd:%d script.fd:%d\n",
			       socket->live.fd, socket->script.fd);
			if (close(socket->live.fd))
				die_perror("close");
		}
		if (socket->protocol == IPPROTO_TCP &&
		        !state->config->is_wire_client &&
		        reset_connection(state, socket))
		{
			die("error reseting connection\n");
		}
		struct socket *dead_socket = socket;
		socket = socket->next;
		socket_free(dead_socket);
	}
}
Example #3
0
int openssl_check_connect(struct connection *conn)
{
	int rc = mbedtls_ssl_handshake(conn->ssl);
	switch (rc) {
	case 0: /* success */
		conn->connected = 1;
		set_writable(conn);
		if (verbose)
			printf("Ciphersuite is %s\n",
				   mbedtls_ssl_get_ciphersuite(conn->ssl));
		return 0;
	case MBEDTLS_ERR_SSL_WANT_READ:
		set_readable(conn);
		return 0;
	case MBEDTLS_ERR_SSL_WANT_WRITE:
		set_writable(conn);
		return 0;
	case MBEDTLS_ERR_NET_CONN_RESET:
		reset_connection(conn);
		return 1;
	default:
		printf("Not read or write 0x%x\n", rc);
		return 1;
	}
}
Example #4
0
/* Close all sockets, free all the socket structs, and send a RST
 * packet to clean up kernel state for each connection.
 * TODO(ncardwell): centralize error handling and ensure test errors
 * always result in a call to these clean-up functions, so we can make
 * sure to reset connections in all cases.
 */
static void close_all_sockets(struct state *state)
{
	struct socket *socket = state->sockets;
	while (socket != NULL) {
		if (socket->live.fd >= 0 && !socket->is_closed) {
			assert(socket->script.fd >= 0);
			DEBUGP("closing struct state socket "
			       "live.fd:%d script.fd:%d\n",
			       socket->live.fd, socket->script.fd);
			if (close(socket->live.fd))
				die_perror("close");
		}
		if ((socket->state != SOCKET_INIT) &&
		    (socket->state != SOCKET_NEW) &&
		    (socket->state != SOCKET_PASSIVE_LISTENING) &&
		    (state->config->is_wire_client == false)) {
			switch (socket->protocol) {
			case IPPROTO_TCP:
				if (reset_connection(state, socket) != STATUS_OK)
					die("error reseting connection\n");
				break;
			case IPPROTO_SCTP:
				if (abort_association(state, socket) != STATUS_OK)
					die("error aborting association\n");
				break;
			default:
				break;
			}
		}
		struct socket *dead_socket = socket;
		socket = socket->next;
		socket_free(dead_socket);
	}
}
Example #5
0
static void
read_cb(int fd, void *arg)
{
    struct argos_net_conn *conn = arg;

    /*
     * We only want to do reads if conn->state == NET_CONN_CONNECTED, but we
     * don't assert() this because its possible for this socket to be selected
     * simultaneously for both a read and a write and then for our state to
     * change during the write attempt.
     */
    if (conn->state != ARGOS_NET_CONN_CONNECTED)
        return;

    ssize_t len = recv(conn->sock, buffer_tail(conn->inbuf), buffer_remaining(conn->inbuf), 0);
    if (len == -1) {
        if (IS_NETWORK_ERROR(errno)) {
            /* network error; reset our connection */
            orion_log_warn_errno("recv");
            reset_connection(conn, 0);
        } else if (errno == EINTR) {
            /* don't care; ignore it */
        } else {
            /* anything else is a fatal error */
            orion_log_crit_errno("recv");
            kill_connection(conn);
            orion_log_crit("unexpected recv() error; connection is now dead");
        }
    } else if (len == 0) {
        /* EOF received (maybe other end is shutting down?) */
        orion_log_info("EOF received from remote end - closing socket");
        if (buffer_len(conn->inbuf) > 0)
            orion_log_warn("incomplete message received (inbuflen=%d)",
                buffer_len(conn->inbuf));
        reset_connection(conn, 1 /* flush buffers */);
    } else {
        /* ok, we read some data into the inbuf; update the buffer */
        int rv = buffer_expand(conn->inbuf, len);
        if (rv == -1) KABOOM("buffer_expand");

        conn->bytes_recv += len;

        /* now process (i.e. look for complete messages in) the inbuf */
        process_inbuf(conn);
    }
}
Example #6
0
static ssize_t
socket_send(struct argos_net_conn *conn, const void *msg, size_t len)
{
#if ARGOS_NET_TRACE_IO
    struct timeval start;
    if (gettimeofday(&start, NULL) != 0) {
        orion_log_crit_errno("gettimeofday");
        return -1;
    }
#endif /* #if ARGOS_NET_TRACE_IO */

    ssize_t sentlen = send(conn->sock, msg, len, 0);
    if (sentlen == -1) {
        if (IS_NETWORK_ERROR(errno)) {
            /* network error; reset our connection */
            orion_log_warn_errno("send() failed");
            reset_connection(conn, 0);
        } else {
            /* anything else is a fatal error */
            orion_log_crit_errno("send");
            kill_connection(conn);
            orion_log_crit("unexpected send() error; connection is now dead");
        }

        return -1;
    } else {
        /* send() succeeded */
        assert(sentlen > 0);

        /* this variable is used even if ARGOS_NET_TRACE_IO is false */
        struct timeval end;
        if (gettimeofday(&end, NULL) != 0) {
            orion_log_crit_errno("gettimeofday");
            return -1;
        }

#if ARGOS_NET_TRACE_IO
        struct timeval elapsed;
        orion_time_subtract(&end, &start, &elapsed);
        float elapsed_msec = elapsed.tv_sec*1000 + (float)elapsed.tv_usec/1000;

        orion_log_debug("sent %u bytes in %.2f ms (%.2f MB/s); requested %u",
            sentlen, elapsed_msec, ((sentlen/elapsed_msec)*1000)/(1024*1024), len);
#endif /* #if ARGOS_NET_TRACE_IO */

        conn->bytes_sent += sentlen;
        conn->last_send = end;
        conn->stall_logged = 0;
        return sentlen;
    }
}
Example #7
0
void
i2c_udp_periodic(void)
{
  if(STATSI2C.timeout == 1){
    i2c_master_disable();
    reset_connection(uip_udp_conn);
    /* FIXME:   PORTC &= ~_BV(PC2); */
  }
  if(STATSI2C.timeout > 0)
    STATSI2C.timeout--;
    
  /* error detection on i2c bus */
  if((TWSR & 0xF8) == 0x00)
    i2c_master_disable();
}
Example #8
0
static void
handle_connect(struct argos_net_conn *conn)
{
    assert(conn->state == ARGOS_NET_CONN_CONNECTING);

    /*
     * connect() completed, but did it succeed or fail?  getpeername() will
     * tell us.  reference: http://cr.yp.to/docs/connect.html
     */
    struct sockaddr_in sin;
    socklen_t slen = sizeof(sin);
    if (getpeername(conn->sock, (struct sockaddr*)&sin, &slen) == -1) {
        if (errno == ENOTCONN) {
            /* connect failed; ok now use error slippage to get the real error */
            char c;
            int rv = read(conn->sock, &c, 1);
            assert(rv == -1);
            handle_connect_failure(conn);
        } else if (errno == ECONNRESET) {
            /* 
             * not sure if this can actually happen - perhaps with perfect
             * timing (connection lost right before we call getpeername)
             */
            orion_log_warn_errno("getpeername");
            reset_connection(conn, 0);
        } else {
            /* this is unexpected... */
            orion_log_crit_errno("getpeername");
            kill_connection(conn);
            orion_log_crit("unexpected getpeername() error after asynchronous"
                " connect() selected for writability; connection is now dead");
        }
    } else {
        /* connect succeeded */
        orion_log_info("connect() succeeded asynchronously");
        handle_connect_success(conn);
    }
}
Example #9
0
void 
i2c_udp_init(uip_udp_conn_t *i2c_conn)
{
  reset_connection(i2c_conn);
}
Example #10
0
/*
* child main loop
*/
void do_child(int unix_fd, int inet_fd)
{
	POOL_CONNECTION *frontend;
	POOL_CONNECTION_POOL *backend;
	struct timeval now;
	struct timezone tz;
	struct timeval timeout;
	static int connected;		/* non 0 if has been accepted connections from frontend */
	int connections_count = 0;	/* used if child_max_connections > 0 */
	int found;
	char psbuf[NI_MAXHOST + 128];

	pool_debug("I am %d", getpid());

	/* Identify myself via ps */
	init_ps_display("", "", "", "");

	/* set up signal handlers */
	signal(SIGALRM, SIG_DFL);
	signal(SIGTERM, die);
	signal(SIGINT, die);
	signal(SIGHUP, reload_config_handler);
	signal(SIGQUIT, die);
	signal(SIGCHLD, SIG_DFL);
	signal(SIGUSR1, close_idle_connection);
	signal(SIGUSR2, wakeup_handler);
	signal(SIGPIPE, SIG_IGN);

#ifdef NONE_BLOCK
	/* set listen fds to none-blocking */
	pool_set_nonblock(unix_fd);
	if (inet_fd)
	{
		pool_set_nonblock(inet_fd);
	}
#endif

	/* Initialize my backend status */
	pool_initialize_private_backend_status();

	/* Initialize per process context */
	pool_init_process_context();

	/* initialize random seed */
	gettimeofday(&now, &tz);
#if defined(sun) || defined(__sun)
	srand((unsigned int) now.tv_usec);
#else
	srandom((unsigned int) now.tv_usec);
#endif

	/* initialize system db connection */
	init_system_db_connection();

	/* initialize connection pool */
	if (pool_init_cp())
	{
		child_exit(1);
	}

	/*
	 * Open pool_passwd in child process.  This is necessary to avoid the
	 * file descriptor race condition reported in [pgpool-general: 1141].
	 */
	if (strcmp("", pool_config->pool_passwd))
	{
		pool_reopen_passwd_file();
	}

	timeout.tv_sec = pool_config->child_life_time;
	timeout.tv_usec = 0;

	for (;;)
	{
		StartupPacket *sp;

		idle = 1;

		/* pgpool stop request already sent? */
		check_stop_request();

		/* Check if restart request is set because of failback event
		 * happend.  If so, exit myself with exit code 1 to be
		 * restarted by pgpool parent.
		 */
		if (pool_get_my_process_info()->need_to_restart)
		{
			pool_log("do_child: failback event found. restart myself.");
			pool_get_my_process_info()->need_to_restart = 0;
			child_exit(1);
		}

		accepted = 0;

		/* perform accept() */
		frontend = do_accept(unix_fd, inet_fd, &timeout);

		if (frontend == NULL)	/* connection request from frontend timed out */
		{
			/* check select() timeout */
			if (connected && pool_config->child_life_time > 0 &&
				timeout.tv_sec == 0 && timeout.tv_usec == 0)
			{
				pool_debug("child life %d seconds expired", pool_config->child_life_time);
				/*
				 * Doesn't need to call this. child_exit() calls it.
				 * send_frontend_exits();
				 */
				child_exit(2);
			}
			continue;
		}

		/* set frontend fd to blocking */
		pool_unset_nonblock(frontend->fd);

		/* reset busy flag */
		idle = 0;

		/* check backend timer is expired */
		if (backend_timer_expired)
		{
			pool_backend_timer();
			backend_timer_expired = 0;
		}

		/* read the startup packet */
	retry_startup:
		sp = read_startup_packet(frontend);
		if (sp == NULL)
		{
			/* failed to read the startup packet. return to the accept() loop */
			pool_close(frontend);
			connection_count_down();
			continue;
		}

		/* cancel request? */
		if (sp->major == 1234 && sp->minor == 5678)
		{
			cancel_request((CancelPacket *)sp->startup_packet);

			pool_close(frontend);
			pool_free_startup_packet(sp);
			connection_count_down();
			continue;
		}

		/* SSL? */
		if (sp->major == 1234 && sp->minor == 5679 && !frontend->ssl_active)
		{
			pool_debug("SSLRequest from client");
			pool_ssl_negotiate_serverclient(frontend);
			goto retry_startup;
		}

		if (pool_config->enable_pool_hba)
		{
			/*
			 * do client authentication.
			 * Note that ClientAuthentication does not return if frontend
			 * was rejected; it simply terminates this process.
			 */
			frontend->protoVersion = sp->major;
			frontend->database = strdup(sp->database);
			if (frontend->database == NULL)
			{
				pool_error("do_child: strdup failed: %s\n", strerror(errno));
				child_exit(1);
			}
			frontend->username = strdup(sp->user);
			if (frontend->username == NULL)
			{
				pool_error("do_child: strdup failed: %s\n", strerror(errno));
				child_exit(1);
			}
			ClientAuthentication(frontend);
		}

		/*
		 * Ok, negotiation with frontend has been done. Let's go to the
		 * next step.  Connect to backend if there's no existing
		 * connection which can be reused by this frontend.
		 * Authentication is also done in this step.
		 */

		/* Check if restart request is set because of failback event
		 * happend.  If so, close idle connections to backend and make
		 * a new copy of backend status.
		 */
		if (pool_get_my_process_info()->need_to_restart)
		{
			pool_log("do_child: failback event found. discard existing connections");
			pool_get_my_process_info()->need_to_restart = 0;
			close_idle_connection(0);
			pool_initialize_private_backend_status();
		}

		/*
		 * if there's no connection associated with user and database,
		 * we need to connect to the backend and send the startup packet.
		 */

		/* look for existing connection */
		found = 0;
		backend = pool_get_cp(sp->user, sp->database, sp->major, 1);

		if (backend != NULL)
		{
			found = 1;

			/* existing connection associated with same user/database/major found.
			 * however we should make sure that the startup packet contents are identical.
			 * OPTION data and others might be different.
			 */
			if (sp->len != MASTER_CONNECTION(backend)->sp->len)
			{
				pool_debug("do_child: connection exists but startup packet length is not identical");
				found = 0;
			}
			else if(memcmp(sp->startup_packet, MASTER_CONNECTION(backend)->sp->startup_packet, sp->len) != 0)
			{
				pool_debug("do_child: connection exists but startup packet contents is not identical");
				found = 0;
			}

			if (found == 0)
			{
				/* we need to discard existing connection since startup packet is different */
				pool_discard_cp(sp->user, sp->database, sp->major);
				backend = NULL;
			}
		}

		if (backend == NULL)
		{
			/* create a new connection to backend */
			if ((backend = connect_backend(sp, frontend)) == NULL)
			{
				connection_count_down();
				continue;
			}
		}

		else
		{
			/* reuse existing connection */
			if (!connect_using_existing_connection(frontend, backend, sp))
				continue;
		}

		connected = 1;

 		/* show ps status */
		sp = MASTER_CONNECTION(backend)->sp;
		snprintf(psbuf, sizeof(psbuf), "%s %s %s idle",
				 sp->user, sp->database, remote_ps_data);
		set_ps_display(psbuf, false);

		/*
		 * Initialize per session context
		 */
		pool_init_session_context(frontend, backend);

		/* Mark this connection pool is connected from frontend */
		pool_coninfo_set_frontend_connected(pool_get_process_context()->proc_id, pool_pool_index());

		/* query process loop */
		for (;;)
		{
			POOL_STATUS status;

			status = pool_process_query(frontend, backend, 0);

			sp = MASTER_CONNECTION(backend)->sp;

			switch (status)
			{
				/* client exits */
				case POOL_END:
					/*
					 * do not cache connection if:
					 * pool_config->connection_cahe == 0 or
					 * database name is template0, template1, postgres or regression
					 */
					if (pool_config->connection_cache == 0 ||
						!strcmp(sp->database, "template0") ||
						!strcmp(sp->database, "template1") ||
						!strcmp(sp->database, "postgres") ||
						!strcmp(sp->database, "regression"))
					{
						reset_connection();
						pool_close(frontend);
						pool_send_frontend_exits(backend);
						pool_discard_cp(sp->user, sp->database, sp->major);
					}
					else
					{
						POOL_STATUS status1;

						/* send reset request to backend */
						status1 = pool_process_query(frontend, backend, 1);
						pool_close(frontend);

						/* if we detect errors on resetting connection, we need to discard
						 * this connection since it might be in unknown status
						 */
						if (status1 != POOL_CONTINUE)
						{
							pool_debug("error in resetting connections. discarding connection pools...");
							pool_send_frontend_exits(backend);
							pool_discard_cp(sp->user, sp->database, sp->major);
						}
						else
							pool_connection_pool_timer(backend);
					}
					break;

				/* error occurred. discard backend connection pool
                   and disconnect connection to the frontend */
				case POOL_ERROR:
					pool_log("do_child: exits with status 1 due to error");
					child_exit(1);
					break;

				/* fatal error occurred. just exit myself... */
				case POOL_FATAL:
					notice_backend_error(1);
					child_exit(1);
					break;

				/* not implemented yet */
				case POOL_IDLE:
					do_accept(unix_fd, inet_fd, &timeout);
					pool_debug("accept while idle");
					break;

				default:
					break;
			}

			if (status != POOL_CONTINUE)
				break;
		}

		/* Destroy session context */
		pool_session_context_destroy();

		/* Mark this connection pool is not connected from frontend */
		pool_coninfo_unset_frontend_connected(pool_get_process_context()->proc_id, pool_pool_index());

		accepted = 0;
		connection_count_down();

		timeout.tv_sec = pool_config->child_life_time;
		timeout.tv_usec = 0;

		/* increment queries counter if necessary */
		if ( pool_config->child_max_connections > 0 )
			connections_count++;

		/* check if maximum connections count for this child reached */
		if ( ( pool_config->child_max_connections > 0 ) &&
			( connections_count >= pool_config->child_max_connections ) )
		{
			pool_log("child exiting, %d connections reached", pool_config->child_max_connections);
			send_frontend_exits();
			child_exit(2);
		}
	}
	child_exit(0);
}
Example #11
0
//==========================================================================================================
// Run multiple tests. Control messagaes are sent to tell mserver which scenario to run. After the run a
// message is sent back to indicate success or failure.
// Special message "bye" tells mserver to quit.
//==========================================================================================================
void MServer::run(int argc, char * argv[])
{
    bool last_failed = false;
    
    try
    {
        process_args(argc, argv);
        sip_connection = new SipConnection(vars[SERVER_IP], stoi(vars[SERVER_PORT]));
        ctrl_connection = new ControlConnection(vars[SERVER_IP], stoi(vars[CONTROL_PORT]));
        
        //--------------------------------------------------------------------------------------------------
        // Run tests until a "bye" control message is received
        //--------------------------------------------------------------------------------------------------
        while(true)
        {
            set_log_file(get_value(RUN_DIR) + "/mserver.log"); // Set the log file back to the global log file between tests

            //----------------------------------------------------------------------------------------------
            // Get and process a control message (indicating which scenario to run, etc.)
            //----------------------------------------------------------------------------------------------
            string ctrl_msg = ctrl_connection->get_message();
            
            if(ctrl_msg == "bye")
            {
                break;
            }
            
            if(ctrl_msg == "awake?")
            {
                ctrl_connection->send_message("yes");
                continue;
            }

            reset_connection(last_failed); // Go back to original ip, start listening if stopped
            last_failed = false;
            
            map<string, string> script_vars;
            process_control_message(ctrl_msg, script_vars);
            
            //----------------------------------------------------------------------------------------------
            // Run the scenario
            //----------------------------------------------------------------------------------------------
            try
            {
                ScriptReader reader(get_value(SCENARIO), script_vars);
                sip_connection->check_no_pending_messages();
            }
            catch(string err) // Error caught here is a test error: report it and continue
            {
                cout << endl << err << endl;
                ctrl_connection->send_message(err);
                last_failed = true;
                continue;
            }
            
            ctrl_connection->send_message("success"); // Test succeeded as far as mserver is concerned
        }
    }
    catch (string err) // Error caught here is fatal, and mserver can't run anymore
    {
        if(!log_file_set)
        {
            // This will be in the directory from which the executable was run. This is to catch any messages that
            // occur before the run dir is known
            set_log_file("mserver.log");
        }
        
        cout << endl << err << endl;
        exit(-1);
    }
}
Example #12
0
static void
process_inbuf(struct argos_net_conn *conn)
{
    while (buffer_len(conn->inbuf) >= sizeof(struct argos_net_minimal_msg)) {
        struct argos_net_minimal_msg *header =
            (struct argos_net_minimal_msg *)buffer_head(conn->inbuf);

        uint16_t msgtype = ntohs(header->msgtype);
        uint32_t msglen = ntohl(header->msglen);

        /* check that message type and length are valid */
        if (ARGOS_NET_VALIDATE_MSGTYPE(msgtype) == 0) {
            orion_log_crit("invalid message type received; type=%hu, len=%u",
                msgtype, msglen);
            reset_connection(conn, 1 /* flush buffers */);
            return;
        }

        if (ARGOS_NET_VALIDATE_MSGLEN(msgtype, msglen) == 0) {
            orion_log_crit("invalid message len received; type=%hu, len=%u",
                msgtype, msglen);
            reset_connection(conn, 1 /* flush buffers */);
            return;
        }

        if (msglen > buffer_len(conn->inbuf)) {
            /* complete message not yet received */
            if (msglen > buffer_size(conn->inbuf)) {
                /* error - message is bigger than the entire inbuf */
                orion_log_err("inbuf too small for msgtype %hu (len=%u)",
                    msgtype, msglen);
                reset_connection(conn, 1 /* flush buffers */);
                return;
            }

            /* wait for more bytes to arrive on socket */
            break;
        }

        /* ok great, message length must be valid - process it */
        switch (msgtype) {
        case ARGOS_NET_CLOSECONN_MSGTYPE: {
            struct argos_net_closeconn_msg msg;
            int rv = buffer_read(conn->inbuf, &msg, sizeof(msg));
            assert(rv >= 0);

            orion_log_info("received close-connection message from server");
            reset_connection(conn, 1 /* flush buffers */);
            break;
        }

        case ARGOS_NET_ERROR_MSGTYPE: {
            struct argos_net_error_msg msg;
            int rv = buffer_read(conn->inbuf, &msg, sizeof(msg));
            assert(rv >= 0);

            char buf[ARGOS_NET_MAX_ERR_LEN+1];
            ssize_t bodylen = msglen - sizeof(msg);
            rv = buffer_read(conn->inbuf, buf, bodylen);
            assert(rv >= 0);
            buf[bodylen] = '\0';

            if (conn->errhandler != NULL)
                conn->errhandler(ntohs(msg.errnum), buf, conn->errhandler_user);
            else
                orion_log_err("[server] %s (%s)", strerror(ntohs(msg.errnum)),
                    buf);
            break;
        }

        case ARGOS_NET_HANDSHAKE_MSGTYPE: {
            struct argos_net_handshake_msg msg;
            int rv = buffer_read(conn->inbuf, &msg, sizeof(msg));
            assert(rv >= 0);

            /* sniffers should never receive handshake messages */
            orion_log_crit("received handshake message from server");
            reset_connection(conn, 1 /* flush buffers */);
            break;
        }

        case ARGOS_NET_PCAP_MSGTYPE: {
            struct argos_net_pcap_msg msg;
            int rv = buffer_read(conn->inbuf, &msg, sizeof(msg));
            assert(rv >= 0);

            size_t bodylen = msglen - sizeof(msg);
            assert(bodylen == ntohl(msg.caplen));

            if (conn->pkthandler == NULL) {
                int rv = buffer_discard(conn->inbuf, bodylen);
                assert(rv >= 0);
                break;
            }

            struct pcap_pkthdr pcap_hdr;
            pcap_hdr.len = ntohl(msg.pktlen);
            pcap_hdr.caplen = ntohl(msg.caplen);
            pcap_hdr.ts.tv_sec = ntohl(msg.ts_sec);
            pcap_hdr.ts.tv_usec = ntohl(msg.ts_usec);

            /*
             * index directly into buffer if possible (i.e. if the data
             * doesn't wrap in the buffer)
             */
            if (buffer_len(conn->inbuf) >= bodylen) {
                conn->pkthandler(&pcap_hdr, buffer_head(conn->inbuf),
                    conn->pkthandler_user);
                buffer_discard(conn->inbuf, bodylen);
            } else {
                /* data wraps; need to copy into a temporary buffer */
                u_char tempbuf[ARGOS_NET_MAX_PKT_LEN];
                buffer_read(conn->inbuf, tempbuf, bodylen);
                conn->pkthandler(&pcap_hdr, tempbuf, conn->pkthandler_user);
            }
            break;
        }

        case ARGOS_NET_SETBPF_MSGTYPE: {
            struct argos_net_setbpf_msg msg;
            int rv = buffer_read(conn->inbuf, &msg, sizeof(msg));
            assert(rv >= 0);

            char buf[ARGOS_NET_MAX_BPF_LEN+1];
            size_t bodylen = msglen - sizeof(msg);
            rv = buffer_read(conn->inbuf, buf, bodylen);
            assert(rv >= 0);
            buf[bodylen] = '\0';

            if (conn->bpfhandler != NULL)
                conn->bpfhandler(buf, conn->bpfhandler_user);
            /* else, just discard and ignore */
            break;
        }

        case ARGOS_NET_SETCHAN_MSGTYPE: {
            struct argos_net_setchan_msg msg;
            int rv = buffer_read(conn->inbuf, &msg, sizeof(msg));
            assert(rv >= 0);

            if (conn->chanhandler != NULL)
                conn->chanhandler(ntohs(msg.chan), conn->chanhandler_user);
            /* else, just discard and ignore */
            break;
        }

        case ARGOS_NET_STARTCLICK_MSGTYPE: {
            struct argos_net_startclick_msg msg;
            int rv = buffer_read(conn->inbuf, &msg, sizeof(msg));
            assert(rv >= 0);

            size_t bodylen = msglen - sizeof(msg);
            char *click_conf = malloc(bodylen+1);
            if (click_conf == NULL) {
                char errmsg[256];
                snprintf(errmsg, sizeof(errmsg), "malloc(%d): %s", bodylen,
                    strerror(errno));

                orion_log_crit_errno("malloc()");
                argos_net_send_errmsg(conn, errno, errmsg);
                kill_connection(conn);
                return;
            }

            rv = buffer_read(conn->inbuf, click_conf, bodylen);
            assert(rv >= 0);
            click_conf[bodylen] = '\0';

            /* is this click config any different from the last one we got? */
            uint32_t key = ntohl(msg.key);
            if (key == conn->click_config_key) {
                /* keys match; we can ignore this message */
                orion_log_debug("click-configuration keys match (%d)", key);
            } else {
                /* keys don't match; need to run this new configuration */
                orion_log_debug("new click-configuration key: %d", key);
                conn->click_config_key = key;
                if (conn->clickhandler != NULL)
                    conn->clickhandler(click_conf, conn->clickhandler_user);
            }

            free(click_conf);
            break;
        }

        case ARGOS_NET_STATS_MSGTYPE: {
            struct argos_net_stats_msg msg;
            int rv = buffer_read(conn->inbuf, &msg, sizeof(msg));
            assert(rv >= 0);

            orion_log_warn("received stats message from server");
            break;
        }

        default:
            orion_log_crit("process_inbuf() of net.c out of sync with net.h;"
                " no switch case for msgtype %hu", msgtype);
            kill_connection(conn);
        }
    }
}
Example #13
0
static int
handle_connect_failure(struct argos_net_conn *conn)
{
    switch (errno) {
        /* these errors indicate some kind of programming error */
    case EBADF:
    case ENOTSOCK:
    case EAFNOSUPPORT:
    case EFAULT:
        /* fall through */

        /*
         * generally, these are non-fatal, but should never happen in this
         * code; if they do, this indicates a programming error
         */
    case EISCONN:
    case EALREADY:
        orion_log_crit_errno("connect");
        kill_connection(conn);
        orion_log_crit("unexpected connect() error; connection is now dead");
        return -1;
        
        /* these are transient errors; we retry connecting */
    case EADDRNOTAVAIL:
    case ETIMEDOUT:
    case ECONNREFUSED:
    case ENETUNREACH:
    case EHOSTUNREACH:
    case EADDRINUSE:
    case ECONNRESET:

        /*
         * EAGAIN is NOT the same as EINPROGRESS; it means that the server's
         * connection backlog is full
         */
    case EAGAIN:
        if (!conn->connect_failed) {
            orion_log_warn_errno("connect");
            conn->connect_failed = 1;
        }
        reset_connection(conn, 0);
        return 0;

        /* these aren't really errors; the connect() should still work */
    case EINPROGRESS:
        /*
         * this errno is ok if returned by connect() itself, but shouldn't be
         * returned via error slippage from a recv() after a failed connect
         */
        if (conn->state == ARGOS_NET_CONN_CONNECTING) {
            orion_log_crit_errno("read after failed connect");
            kill_connection(conn);
            orion_log_crit("unexpected recv() error; connection is now dead");
        }
        /* fall through */

    case EINTR:
        orion_log_debug("connect() in progress (\"%s\")", strerror(errno));
        conn->state = ARGOS_NET_CONN_CONNECTING;
        return 0;

    default:
        /* unknown errno */
        orion_log_crit_errno("read after failed connect");
        orion_log_crit("unexpected connect errno");
        kill_connection(conn);
        return -1;
    }
}