Exemplo n.º 1
0
int main()
{
	apr_initialize();
	apr_pool_t *mempool;
	apr_sockaddr_t *socket_addr;
	apr_socket_t *socket;
	apr_pool_create( &mempool, NULL );
	apr_sockaddr_info_get( &socket_addr, NULL, APR_INET, REPLY_PORT, 0, mempool );
	apr_socket_create( &socket, socket_addr->family, SOCK_STREAM, APR_PROTO_TCP, mempool );
	apr_socket_bind( socket, socket_addr );
	apr_socket_listen( socket, SOMAXCONN );
	apr_socket_t *accepted;
	apr_socket_accept( &accepted, socket, mempool );
	int *replies = (int*)malloc( frl_reply_size );
	apr_size_t len = frl_reply_size;
	do {
		apr_socket_recv( accepted, (char*)replies, &len );
		int *iter_replies = replies+2;
		for ( int i = 0; i < 100; i++, iter_replies+=2 )
		{
			std::cout<<*iter_replies<<" "<<*(iter_replies+1)<<std::endl;
		}
		std::cout<<"The End."<<std::endl;
	} while (1);
	apr_terminate();
	return 0;
}
Exemplo n.º 2
0
static apt_bool_t mrcp_server_agent_listen_socket_create(mrcp_connection_agent_t *agent)
{
	apr_status_t status;
	if(!agent->sockaddr) {
		return FALSE;
	}

	/* create listening socket */
	status = apr_socket_create(&agent->listen_sock, agent->sockaddr->family, SOCK_STREAM, APR_PROTO_TCP, agent->pool);
	if(status != APR_SUCCESS) {
		return FALSE;
	}

	apr_socket_opt_set(agent->listen_sock, APR_SO_NONBLOCK, 0);
	apr_socket_timeout_set(agent->listen_sock, -1);
	apr_socket_opt_set(agent->listen_sock, APR_SO_REUSEADDR, 1);

	status = apr_socket_bind(agent->listen_sock, agent->sockaddr);
	if(status != APR_SUCCESS) {
		apr_socket_close(agent->listen_sock);
		agent->listen_sock = NULL;
		return FALSE;
	}
	status = apr_socket_listen(agent->listen_sock, SOMAXCONN);
	if(status != APR_SUCCESS) {
		apr_socket_close(agent->listen_sock);
		agent->listen_sock = NULL;
		return FALSE;
	}

	return TRUE;
}
Exemplo n.º 3
0
void server_bind_listen(server_t *svr) {
    apr_sockaddr_info_get(&svr->comm->sa, NULL, APR_INET, 
			  svr->comm->port, 0, svr->comm->mp);
/*
    apr_socket_create(&r->s, r->sa->family, SOCK_DGRAM, APR_PROTO_UDP, r->pl_recv);
*/
    apr_socket_create(&svr->comm->s, svr->comm->sa->family, 
		      SOCK_STREAM, APR_PROTO_TCP, svr->comm->mp);
    apr_socket_opt_set(svr->comm->s, APR_SO_NONBLOCK, 1);
    apr_socket_timeout_set(svr->comm->s, -1);
    /* this is useful for a server(socket listening) process */
    apr_socket_opt_set(svr->comm->s, APR_SO_REUSEADDR, 1);
    apr_socket_opt_set(svr->comm->s, APR_TCP_NODELAY, 1);
    
    apr_status_t status = APR_SUCCESS;
    status = apr_socket_bind(svr->comm->s, svr->comm->sa);
    if (status != APR_SUCCESS) {
        LOG_ERROR("cannot bind.");
        printf("%s", apr_strerror(status, malloc(100), 100));
        SAFE_ASSERT(status == APR_SUCCESS);
    }
    status = apr_socket_listen(svr->comm->s, 30000); // This is important!
    if (status != APR_SUCCESS) {
        LOG_ERROR("cannot listen.");
        printf("%s", apr_strerror(status, malloc(100), 100));
        SAFE_ASSERT(status == APR_SUCCESS);
    }
    LOG_INFO("successfuly bind and listen on port %d.", svr->comm->port);
}
Exemplo n.º 4
0
/**
 * Create a listening socket, and listen it.
 */
static apr_status_t do_listen(apr_socket_t **sock, apr_pool_t *mp, int port)
{
    apr_status_t rv;
    apr_socket_t *s;
    apr_sockaddr_t *sa;
    
    rv = apr_sockaddr_info_get(&sa, NULL, APR_INET, port, 0, mp);
    if (rv != APR_SUCCESS) {
        return rv;
    }
    
    rv = apr_socket_create(&s, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp);
    if (rv != APR_SUCCESS) {
        return rv;
    }

    /* it is a good idea to specify socket options explicitly.
     * in this case, we make a blocking socket as the listening socket */
    apr_socket_opt_set(s, APR_SO_NONBLOCK, 0);
    apr_socket_timeout_set(s, 100);
    apr_socket_opt_set(s, APR_SO_REUSEADDR, 1);/* this is useful for a server(socket listening) process */

    rv = apr_socket_bind(s, sa);
    if (rv != APR_SUCCESS) {
        return rv;
    }
    rv = apr_socket_listen(s, DEF_SOCKET_BACKLOG);
    if (rv != APR_SUCCESS) {
        return rv;
    }

    *sock = s;
    return rv;
}
Exemplo n.º 5
0
static apr_socket_t* create_listen_sock(apr_pool_t *mp, unsigned short channel)
{
    apr_status_t rv;
    apr_socket_t *s;
    apr_sockaddr_t *sa;

    rv = apr_sockaddr_info_get(&sa, NULL, APR_INET, DEF_LISTEN_PORT+channel, 0, mp); // Create apr_sockaddr_t from hostname, address family, and port.
    if (rv != APR_SUCCESS)
        return NULL;

    rv = apr_socket_create(&s, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp); //CREATE A SOCKET
    if (rv != APR_SUCCESS)
        return NULL;

    /* non-blocking socket */
    apr_socket_opt_set(s, APR_SO_NONBLOCK, 1); //Setup socket options for the specified socke

    apr_socket_timeout_set(s, 0); //Setup socket timeout for the specified socket
    apr_socket_opt_set(s, APR_SO_REUSEADDR, 1);/* this is useful for a server(socket listening) process */

    rv = apr_socket_bind(s, sa); //Bind the socket to its associated port
    if (rv != APR_SUCCESS)
        return NULL;

    rv = apr_socket_listen(s, DEF_SOCKET_BACKLOG); //Listen to a bound socket for connections.
    if (rv != APR_SUCCESS)
        return NULL;

    return s;
}
Exemplo n.º 6
0
apr_status_t serf_listener_create(
    serf_listener_t **listener,
    serf_context_t *ctx,
    const char *host,
    apr_uint16_t port,
    void *accept_baton,
    serf_accept_client_t accept,
    apr_pool_t *pool)
{
    apr_sockaddr_t *sa;
    apr_status_t rv;
    serf_listener_t *l = apr_palloc(pool, sizeof(*l));

    l->ctx = ctx;
    l->baton.type = SERF_IO_LISTENER;
    l->baton.u.listener = l;
    l->accept_func = accept;
    l->accept_baton = accept_baton;

    apr_pool_create(&l->pool, pool);

    rv = apr_sockaddr_info_get(&sa, host, APR_UNSPEC, port, 0, l->pool);
    if (rv)
        return rv;

    rv = apr_socket_create(&l->skt, sa->family,
                           SOCK_STREAM,
#if APR_MAJOR_VERSION > 0
                           APR_PROTO_TCP,
#endif
                           l->pool);
    if (rv)
        return rv;

    rv = apr_socket_opt_set(l->skt, APR_SO_REUSEADDR, 1);
    if (rv)
        return rv;

    rv = apr_socket_bind(l->skt, sa);
    if (rv)
        return rv;

    rv = apr_socket_listen(l->skt, 5);
    if (rv)
        return rv;

    l->desc.desc_type = APR_POLL_SOCKET;
    l->desc.desc.s = l->skt;
    l->desc.reqevents = APR_POLLIN;

    rv = ctx->pollset_add(ctx->pollset_baton,
                            &l->desc, &l->baton);
    if (rv)
        return rv;

    *listener = l;

    return APR_SUCCESS;
}
Exemplo n.º 7
0
/**
 * do_listen -- create a listen socket
 */
apr_status_t do_listen(apr_pollset_t *pollset, apr_hash_t *ht, 
		       apr_pool_t *mp, const char *param)
{
	apr_status_t rv;
	apr_socket_t *s;
	apr_sockaddr_t *sa;
	char **ptr;
	int port;
	
	ptr = str_split_char(param, ":");
	if (ptr == NULL) {
		fprintf(stderr, "Get Null param!\n");
		return APR_EINVAL;
	}
	// then convert param
	port = atoi(ptr[1]);
	if (port < 0)
		return APR_EINVAL;

	rv = apr_sockaddr_info_get(&sa, ptr[0], APR_INET, port, 0, mp);
	if (rv != APR_SUCCESS) {
		return rv;
	}
	
	rv = apr_socket_create(&s, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp);
	if (rv != APR_SUCCESS) {
		return rv;
	}

	/* non-blocking socket */
	apr_socket_opt_set(s, APR_SO_NONBLOCK, 1);
	apr_socket_timeout_set(s, 0);
	apr_socket_opt_set(s, APR_SO_REUSEADDR, 1);/* this is useful for a 
						* server(socket listening) process */

	rv = apr_socket_bind(s, sa);
	if (rv != APR_SUCCESS) {
		return rv;
	}
	rv = apr_socket_listen(s, DEF_SOCKET_BACKLOG);
	if (rv != APR_SUCCESS) {
		return rv;
	}
	// Then.., add it to hash table, listen and connect socket 
	// against a different val, so we can distinguish in the 
	// pollset
	apr_hash_set(ht, s, APR_HASH_KEY_STRING, "S"); // server

	// Then.., if everything is OK, add it to the pollset
	apr_pollfd_t pfd = {mp, APR_POLL_SOCKET, APR_POLLIN, 0, {NULL}, NULL};
	pfd.desc.s = s;
	apr_pollset_add(pollset, &pfd);
	free(ptr);

	return APR_SUCCESS;
	
}
Exemplo n.º 8
0
static void im_ssl_listen(nx_module_t *module)
{
    nx_im_ssl_conf_t *imconf;
    nx_exception_t e;

    imconf = (nx_im_ssl_conf_t *) module->config;

    try
    {
	if ( imconf->listensock == NULL )
	{
	    apr_sockaddr_t *sa;

	    CHECKERR_MSG(apr_socket_create(&(imconf->listensock), APR_INET, SOCK_STREAM,
					   APR_PROTO_TCP, module->input.pool),
			 "couldn't create tcp socket");

	    CHECKERR_MSG(apr_sockaddr_info_get(&sa, imconf->host, APR_INET, imconf->port, 
					       0, module->input.pool),
			 "apr_sockaddr_info failed for %s:%d", imconf->host, imconf->port);
	
	    CHECKERR_MSG(apr_socket_opt_set(imconf->listensock, APR_SO_NONBLOCK, 1),
			 "couldn't set SO_NONBLOCK on listen socket");
	    CHECKERR_MSG(apr_socket_timeout_set(imconf->listensock, 0),
			 "couldn't set socket timeout on listen socket");
	    CHECKERR_MSG(apr_socket_opt_set(imconf->listensock, APR_SO_REUSEADDR, 1),
			 "couldn't set SO_REUSEADDR on listen socket");
	    CHECKERR_MSG(apr_socket_opt_set(imconf->listensock, APR_TCP_NODELAY, 1),
			 "couldn't set TCP_NODELAY on listen socket");
	    CHECKERR_MSG(apr_socket_bind(imconf->listensock, sa),
			 "couldn't bind ssl socket to %s:%d", imconf->host, imconf->port);
	}
        else
	{
	    log_debug("ssl socket already initialized");
	}

	CHECKERR_MSG(apr_socket_listen(imconf->listensock, SOMAXCONN),
		     "couldn't listen to ssl socket on %s:%d",
		     imconf->host, imconf->port);
    
	nx_module_pollset_add_socket(module, imconf->listensock, APR_POLLIN | APR_POLLHUP);
    }
    catch(e)
    {
	if ( imconf->listensock != NULL )
	{
	    apr_socket_close(imconf->listensock);
	    imconf->listensock = NULL;
	}
	apr_pool_clear(module->input.pool);
	rethrow(e);
    }
}
Exemplo n.º 9
0
static int socket_listen(lua_State *L)
{
  lua_apr_socket *object;
  apr_status_t status;
  apr_int32_t backlog = SOMAXCONN;

  object = socket_check(L, 1, 1);
  if (strcmp(lua_tostring(L, 2), "max") != 0)
    backlog = luaL_checkinteger(L, 2);
  status = apr_socket_listen(object->handle, backlog);

  return push_status(L, status);
}
Exemplo n.º 10
0
/*! Create a non-blocking server socket, ready to be passed to
 *  cpe_socket_after_accept().
 *
 *  Parameters are as for apr_sockaddr_info_get(), apr_socket_create(),
 *  apr_socket_bind() and apr_socket_listen().
 *
 */
apr_status_t
cpe_socket_server_create(apr_socket_t **sock, apr_sockaddr_t **sockaddr,
    const char *hostname, apr_port_t port, apr_int32_t backlog,
    apr_pool_t *pool)
{
    apr_status_t    rv;

    CHECK(cpe_socket_client_create(sock, sockaddr, hostname, port, pool));
    CHECK(apr_socket_opt_set(*sock, APR_SO_REUSEADDR, 1));
    CHECK(apr_socket_bind(*sock, *sockaddr));
    CHECK(apr_socket_listen(*sock, backlog));
    return APR_SUCCESS;
}
Exemplo n.º 11
0
apr_socket_t *
create_tcp_server(apr_pool_t *context, int32_t family, apr_port_t port, 
                  char *bind_addr, char *interface, int blocking)
{
  apr_socket_t *sock = create_net_server(context, family, SOCK_STREAM, port,
                                         bind_addr, blocking);
  if(!sock)
    {
      return NULL;
    }
  if(apr_socket_listen(sock, 5) != APR_SUCCESS) 
    {
      return NULL;
    }
  return sock;
}
Exemplo n.º 12
0
/** Create listening socket and add it to pollset */
static apt_bool_t rtsp_server_listening_socket_create(rtsp_server_t *server)
{
	apr_status_t status;
	
	if(!server->sockaddr) {
		return FALSE;
	}

	/* create listening socket */
	status = apr_socket_create(&server->listen_sock, server->sockaddr->family, SOCK_STREAM, APR_PROTO_TCP, server->pool);
	if(status != APR_SUCCESS) {
		return FALSE;
	}

	apr_socket_opt_set(server->listen_sock, APR_SO_NONBLOCK, 0);
	apr_socket_timeout_set(server->listen_sock, -1);
	apr_socket_opt_set(server->listen_sock, APR_SO_REUSEADDR, 1);

	status = apr_socket_bind(server->listen_sock, server->sockaddr);
	if(status != APR_SUCCESS) {
		apr_socket_close(server->listen_sock);
		server->listen_sock = NULL;
		return FALSE;
	}
	status = apr_socket_listen(server->listen_sock, SOMAXCONN);
	if(status != APR_SUCCESS) {
		apr_socket_close(server->listen_sock);
		server->listen_sock = NULL;
		return FALSE;
	}

	/* add listening socket to pollset */
	memset(&server->listen_sock_pfd,0,sizeof(apr_pollfd_t));
	server->listen_sock_pfd.desc_type = APR_POLL_SOCKET;
	server->listen_sock_pfd.reqevents = APR_POLLIN;
	server->listen_sock_pfd.desc.s = server->listen_sock;
	server->listen_sock_pfd.client_data = server->listen_sock;
	if(apt_poller_task_descriptor_add(server->task, &server->listen_sock_pfd) != TRUE) {
		apt_log(RTSP_LOG_MARK,APT_PRIO_WARNING,"Failed to Add Listening Socket to Pollset");
		apr_socket_close(server->listen_sock);
		server->listen_sock = NULL;
		return FALSE;
	}

	return TRUE;
}
Exemplo n.º 13
0
/** Create listening socket and add it to pollset */
static apt_bool_t mrcp_server_agent_listening_socket_create(mrcp_connection_agent_t *agent)
{
	apr_status_t status;
	if(!agent->sockaddr) {
		return FALSE;
	}

	/* create listening socket */
	status = apr_socket_create(&agent->listen_sock, agent->sockaddr->family, SOCK_STREAM, APR_PROTO_TCP, agent->pool);
	if(status != APR_SUCCESS) {
		return FALSE;
	}

	apr_socket_opt_set(agent->listen_sock, APR_SO_NONBLOCK, 0);
	apr_socket_timeout_set(agent->listen_sock, -1);
	apr_socket_opt_set(agent->listen_sock, APR_SO_REUSEADDR, 1);

	status = apr_socket_bind(agent->listen_sock, agent->sockaddr);
	if(status != APR_SUCCESS) {
		apr_socket_close(agent->listen_sock);
		agent->listen_sock = NULL;
		return FALSE;
	}
	status = apr_socket_listen(agent->listen_sock, SOMAXCONN);
	if(status != APR_SUCCESS) {
		apr_socket_close(agent->listen_sock);
		agent->listen_sock = NULL;
		return FALSE;
	}

	/* add listening socket to pollset */
	memset(&agent->listen_sock_pfd,0,sizeof(apr_pollfd_t));
	agent->listen_sock_pfd.desc_type = APR_POLL_SOCKET;
	agent->listen_sock_pfd.reqevents = APR_POLLIN;
	agent->listen_sock_pfd.desc.s = agent->listen_sock;
	agent->listen_sock_pfd.client_data = agent->listen_sock;
	if(apt_poller_task_descriptor_add(agent->task, &agent->listen_sock_pfd) != TRUE) {
		apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add Listening Socket to Pollset [%s]",
			apt_task_name_get(apt_poller_task_base_get(agent->task)));
		apr_socket_close(agent->listen_sock);
		agent->listen_sock = NULL;
		return FALSE;
	}

	return TRUE;
}
Exemplo n.º 14
0
static apr_status_t glassToWall(apr_int16_t port, apr_pool_t *parent)
{
    apr_sockaddr_t *sockAddr;
    apr_socket_t *listener, *accepted;
    apr_status_t rv;

    rv = apr_socket_create(&listener, APR_INET, SOCK_STREAM, APR_PROTO_TCP,
                           parent);
    if (rv != APR_SUCCESS) {
        reportError("Unable to create socket", rv, parent);
        return rv;
    }

    rv = apr_sockaddr_info_get(&sockAddr, "127.0.0.1", APR_UNSPEC,
                               port, 0, parent);
    if (rv != APR_SUCCESS) {
        reportError("Unable to get socket info", rv, parent);
        apr_socket_close(listener);
        return rv;
    }

    if ((rv = apr_socket_bind(listener, sockAddr)) != APR_SUCCESS ||
        (rv = apr_socket_listen(listener, 5)) != APR_SUCCESS) {
        reportError("Unable to bind or listen to socket", rv, parent);
        apr_socket_close(listener);
        return rv;
    }

    for (;;) {
        rv = apr_socket_accept(&accepted, listener, parent);
        if (rv != APR_SUCCESS) {
            reportError("Error accepting on socket", rv, parent);
            break;
        }
        printf("\tAnswering connection\n");
        rv = talkTalk(accepted, parent);
        apr_socket_close(accepted);
        printf("\tConnection closed\n");
        if (rv != APR_SUCCESS)
            break;
    }

    apr_socket_close(listener);
    return APR_SUCCESS;
}
Exemplo n.º 15
0
/* Start a TCP server on port SERV_PORT in thread THREAD. srv_replay is a array
   of action to replay when connection started. replay_count is count of
   actions in srv_replay. */
static apr_status_t prepare_server(test_baton_t *tb,
                                   apr_pool_t *pool)
{
    apr_status_t status;
    apr_socket_t *serv_sock;

    /* create server socket */
#if APR_VERSION_AT_LEAST(1, 0, 0)
    status = apr_socket_create(&serv_sock, APR_INET, SOCK_STREAM, 0, pool);
#else
    status = apr_socket_create(&serv_sock, APR_INET, SOCK_STREAM, pool);
#endif

    if (status != APR_SUCCESS)
        return status;

    apr_socket_opt_set(serv_sock, APR_SO_NONBLOCK, 1);
    apr_socket_timeout_set(serv_sock, 0);
    apr_socket_opt_set(serv_sock, APR_SO_REUSEADDR, 1);

    status = apr_socket_bind(serv_sock, tb->serv_addr);
    if (status != APR_SUCCESS)
        return status;

    /* Start replay from first action. */
    tb->cur_action = 0;
    tb->action_buf_pos = 0;

    /* listen for clients */
    apr_socket_listen(serv_sock, SOMAXCONN);
    if (status != APR_SUCCESS)
        return status;

    tb->serv_sock = serv_sock;
    tb->client_sock = NULL;
    return APR_SUCCESS;
}
Exemplo n.º 16
0
apr_status_t start_test_server(serv_ctx_t *servctx)
{
    apr_status_t status;
    apr_socket_t *serv_sock;

    /* create server socket */
#if APR_VERSION_AT_LEAST(1, 0, 0)
    status = apr_socket_create(&serv_sock, servctx->serv_addr->family,
                               SOCK_STREAM, 0,
                               servctx->pool);
#else
    status = apr_socket_create(&serv_sock, servctx->serv_addr->family,
                               SOCK_STREAM,
                               servctx->pool);
#endif

    if (status != APR_SUCCESS)
        return status;

    apr_socket_opt_set(serv_sock, APR_SO_NONBLOCK, 1);
    apr_socket_timeout_set(serv_sock, 0);
    apr_socket_opt_set(serv_sock, APR_SO_REUSEADDR, 1);

    status = apr_socket_bind(serv_sock, servctx->serv_addr);
    if (status != APR_SUCCESS)
        return status;

    /* listen for clients */
    status = apr_socket_listen(serv_sock, SOMAXCONN);
    if (status != APR_SUCCESS)
        return status;

    servctx->serv_sock = serv_sock;
    servctx->client_sock = NULL;

    return APR_SUCCESS;
}
Exemplo n.º 17
0
int sock_listen(net_sock_t *nsock, int max_pending)
{
    int err;
    network_sock_t *sock = (network_sock_t *)nsock;

    if (sock == NULL) return(1);

    err = apr_socket_listen(sock->fd, max_pending);
    if (err != APR_SUCCESS) return(err);

    //** Create the polling info
    apr_pollset_create(&(sock->pollset), 1, sock->mpool, APR_POLLSET_THREADSAFE);
//  sock->pfd = { sock->mpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, NULL };
    sock->pfd.p = sock->mpool;
    sock->pfd.desc_type = APR_POLL_SOCKET;
    sock->pfd.reqevents = APR_POLLIN;
    sock->pfd.rtnevents = 0;
    sock->pfd.desc.s = sock->fd;
    sock->pfd.client_data = NULL;

    apr_pollset_add(sock->pollset, &(sock->pfd));

    return(0);
}
Exemplo n.º 18
0
static apr_socket_t *setup_socket(abts_case *tc)
{
    apr_status_t rv;
    apr_sockaddr_t *sa;
    apr_socket_t *sock;

    rv = apr_sockaddr_info_get(&sa, "127.0.0.1", APR_INET, 8021, 0, p);
    APR_ASSERT_SUCCESS(tc, "Problem generating sockaddr", rv);

    rv = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, p);
    APR_ASSERT_SUCCESS(tc, "Problem creating socket", rv);

    rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1);
    APR_ASSERT_SUCCESS(tc, "Could not set REUSEADDR on socket", rv);
    
    rv = apr_socket_bind(sock, sa);
    APR_ASSERT_SUCCESS(tc, "Problem binding to port", rv);
    if (rv) return NULL;
                
    rv = apr_socket_listen(sock, 5);
    APR_ASSERT_SUCCESS(tc, "Problem listening on socket", rv);

    return sock;
}
void LLPluginProcessParent::idle(void)
{
	bool idle_again;

	do
	{
		// Give time to network processing
		if(mMessagePipe)
		{
			if(!mMessagePipe->pump())
			{
//				LL_WARNS("Plugin") << "Message pipe hit an error state" << LL_ENDL;
				errorState();
			}
		}

		if((mSocketError != APR_SUCCESS) && (mState <= STATE_RUNNING))
		{
			// The socket is in an error state -- the plugin is gone.
			LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
			errorState();
		}	
		
		// If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
		// USE THIS CAREFULLY, since it can starve other code.  Specifically make sure there's no way to get into a closed cycle and never return.
		// When in doubt, don't do it.
		idle_again = false;
		switch(mState)
		{
			case STATE_UNINITIALIZED:
			break;

			case STATE_INITIALIZED:
			{
	
				apr_status_t status = APR_SUCCESS;
				apr_sockaddr_t* addr = NULL;
				mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
				mBoundPort = 0;
				
				// This code is based on parts of LLSocket::create() in lliosocket.cpp.
				
				status = apr_sockaddr_info_get(
					&addr,
					"127.0.0.1",
					APR_INET,
					0,	// port 0 = ephemeral ("find me a port")
					0,
					gAPRPoolp);
					
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}

				// This allows us to reuse the address on quick down/up. This is unlikely to create problems.
				ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1));
				
				status = apr_socket_bind(mListenSocket->getSocket(), addr);
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}

				// Get the actual port the socket was bound to
				{
					apr_sockaddr_t* bound_addr = NULL;
					if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket())))
					{
						killSockets();
						errorState();
						break;
					}
					mBoundPort = bound_addr->port;	

					if(mBoundPort == 0)
					{
						LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL;
						
						killSockets();
						errorState();
						break;
					}
				}
				
				LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL;

				// Make the listen socket non-blocking
				status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1);
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}

				apr_socket_timeout_set(mListenSocket->getSocket(), 0);
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}
				
				// If it's a stream based socket, we need to tell the OS
				// to keep a queue of incoming connections for ACCEPT.
				status = apr_socket_listen(
					mListenSocket->getSocket(),
					10); // FIXME: Magic number for queue size
					
				if(ll_apr_warn_status(status))
				{
					killSockets();
					errorState();
					break;
				}
				
				// If we got here, we're listening.
				setState(STATE_LISTENING);
			}
			break;
			
			case STATE_LISTENING:
			{
				// Launch the plugin process.
				
				// Only argument to the launcher is the port number we're listening on
				std::stringstream stream;
				stream << mBoundPort;
				mProcess.addArgument(stream.str());
				if(mProcess.launch() != 0)
				{
					errorState();
				}
				else
				{
					if(mDebug)
					{
						#if LL_DARWIN
						// If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
						
						// The command we're constructing would look like this on the command line:
						// osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'

						std::stringstream cmd;
						
						mDebugger.setExecutable("/usr/bin/osascript");
						mDebugger.addArgument("-e");
						mDebugger.addArgument("tell application \"Terminal\"");
						mDebugger.addArgument("-e");
						cmd << "set win to do script \"gdb -pid " << mProcess.getProcessID() << "\"";
						mDebugger.addArgument(cmd.str());
						mDebugger.addArgument("-e");
						mDebugger.addArgument("do script \"continue\" in win");
						mDebugger.addArgument("-e");
						mDebugger.addArgument("end tell");
						mDebugger.launch();

						#endif
					}
					
					// This will allow us to time out if the process never starts.
					mHeartbeat.start();
					mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
					setState(STATE_LAUNCHED);
				}
			}
			break;

			case STATE_LAUNCHED:
				// waiting for the plugin to connect
				if(pluginLockedUpOrQuit())
				{
					errorState();
				}
				else
				{
					// Check for the incoming connection.
					if(accept())
					{
						// Stop listening on the server port
						mListenSocket.reset();
						setState(STATE_CONNECTED);
					}
				}
			break;
			
			case STATE_CONNECTED:
				// waiting for hello message from the plugin

				if(pluginLockedUpOrQuit())
				{
					errorState();
				}
			break;

			case STATE_HELLO:
				LL_DEBUGS("Plugin") << "received hello message" << llendl;
				
				// Send the message to load the plugin
				{
					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin");
					message.setValue("file", mPluginFile);
					message.setValue("user_data_path", mUserDataPath);
					sendMessage(message);
				}

				setState(STATE_LOADING);
			break;
			
			case STATE_LOADING:
				// The load_plugin_response message will kick us from here into STATE_RUNNING
				if(pluginLockedUpOrQuit())
				{
					errorState();
				}
			break;
			
			case STATE_RUNNING:
				if(pluginLockedUpOrQuit())
				{
					errorState();
				}
			break;
			
			case STATE_EXITING:
				if(!mProcess.isRunning())
				{
					setState(STATE_CLEANUP);
				}
				else if(pluginLockedUp())
				{
					LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << llendl;
					errorState();
				}
			break;

			case STATE_LAUNCH_FAILURE:
				if(mOwner != NULL)
				{
					mOwner->pluginLaunchFailed();
				}
				setState(STATE_CLEANUP);
			break;

			case STATE_ERROR:
				if(mOwner != NULL)
				{
					mOwner->pluginDied();
				}
				setState(STATE_CLEANUP);
			break;
			
			case STATE_CLEANUP:
				// Don't do a kill here anymore -- closing the sockets is the new 'kill'.
				mProcess.orphan();
				killSockets();
				setState(STATE_DONE);
			break;
			
			
			case STATE_DONE:
				// just sit here.
			break;
			
		}
	
	} while (idle_again);
}
Exemplo n.º 20
0
// static
LLSocket::ptr_t LLSocket::create(EType type, U16 port)
{
	apr_status_t status = APR_EGENERAL;
	LLSocket::ptr_t rv(new LLSocket);

	if(STREAM_TCP == type)
	{
		status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, rv->mPool());
	}
	else if(DATAGRAM_UDP == type)
	{
		status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, rv->mPool());
	}
	else
	{
		rv.reset();
		return rv;
	}
	if(ll_apr_warn_status(status))
	{
		rv->mSocket = NULL;
		rv.reset();
		return rv;
	}
	if(port > 0)
	{
		apr_sockaddr_t* sa = NULL;
		status = apr_sockaddr_info_get(
			&sa,
			APR_ANYADDR,
			APR_UNSPEC,
			port,
			0,
			rv->mPool());
		if(ll_apr_warn_status(status))
		{
			rv.reset();
			return rv;
		}
		// This allows us to reuse the address on quick down/up. This
		// is unlikely to create problems.
		ll_apr_warn_status(apr_socket_opt_set(rv->mSocket, APR_SO_REUSEADDR, 1));
		status = apr_socket_bind(rv->mSocket, sa);
		if(ll_apr_warn_status(status))
		{
			rv.reset();
			return rv;
		}
		LL_DEBUGS() << "Bound " << ((DATAGRAM_UDP == type) ? "udp" : "tcp")
				 << " socket to port: " << sa->port << LL_ENDL;
		if(STREAM_TCP == type)
		{
			// If it's a stream based socket, we need to tell the OS
			// to keep a queue of incoming connections for ACCEPT.
			LL_DEBUGS() << "Setting listen state for socket." << LL_ENDL;
			status = apr_socket_listen(
				rv->mSocket,
				LL_DEFAULT_LISTEN_BACKLOG);
			if(ll_apr_warn_status(status))
			{
				rv.reset();
				return rv;
			}
		}
	}
	else
	{
		// we need to indicate that we have an ephemeral port if the
		// previous calls were successful. It will
		port = PORT_EPHEMERAL;
	}
	rv->mPort = port;
	rv->setNonBlocking();
	return rv;
}
Exemplo n.º 21
0
void* thread_socket_pipe_receiver(apr_thread_t* thd, void* data)
{
	frl_socket_pipe* pipe = (frl_socket_pipe*)data;

	apr_status_t state;

	apr_socket_t* listen_sock;
	apr_socket_create(&listen_sock, pipe->sock_addr->family, SOCK_STREAM, APR_PROTO_TCP, pipe->sockpool);
	apr_socket_opt_set(listen_sock, APR_SO_NONBLOCK, 1);
	apr_socket_timeout_set(listen_sock, 0);
	apr_socket_opt_set(listen_sock, APR_SO_REUSEADDR, 1);
	pipe->recv_state = apr_socket_bind(listen_sock, pipe->sock_addr);
	F_ERROR_IF_RUN(APR_SUCCESS != pipe->recv_state, return NULL, "[frl_socket_pipe::thread_socket_pipe_receiver]: Socket Binding Error: %d\n", pipe->recv_state);
	pipe->recv_state = apr_socket_listen(listen_sock, SOMAXCONN);
	F_ERROR_IF_RUN(APR_SUCCESS != pipe->recv_state, return NULL, "[frl_socket_pipe::thread_socket_pipe_receiver]: Socket Listen Error: %d\n", pipe->recv_state);
	apr_uint32_t hash;
	apr_pollset_t* pollset;
	apr_pollset_create(&pollset, pipe->replicate+2, pipe->sockpool, 0);
	apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, NULL };
	pfd.desc.s = listen_sock;
	apr_pollset_add(pollset, &pfd);
	do {
		// the fun loop
		apr_int32_t total;
		const apr_pollfd_t* ret_pfd;
		pipe->recv_state = apr_pollset_poll(pollset, SOCKET_PIPE_POLL_TIMEOUT, &total, &ret_pfd);
		if (APR_SUCCESS == pipe->recv_state)
		{
			for (int i = 0; i < total; i++)
			{
				if (ret_pfd[i].desc.s == listen_sock)
				{
					apr_socket_t* accept_sock;
					state = apr_socket_accept(&accept_sock, listen_sock, pipe->sockpool);
					F_ERROR_IF_RUN(APR_SUCCESS != state, continue, "[frl_socket_pipe::thread_socket_pipe_receiver]: Socket Accept Error: %d\n", state);
					// accept connection, initiate recv
					frl_pipe_state_t* pipestate = (frl_pipe_state_t*)frl_slab_palloc(pipe->statepool);
					apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate };
					pipestate->state = FRL_PIPE_READ_HEADER_START;
					pipestate->reader = (char*)&pipestate->header;
					pipestate->offset = 0;
					pipestate->size = SIZEOF_FRL_PIPE_HEADER_T;
					pfd.desc.s = accept_sock;
					apr_socket_opt_set(accept_sock, APR_SO_NONBLOCK, 1);
					apr_socket_timeout_set(accept_sock, 0);
					apr_pollset_add(pollset, &pfd);
				} else {
					if (ret_pfd[i].rtnevents & APR_POLLIN)
					{
						frl_pipe_state_t* pipestate = (frl_pipe_state_t*)ret_pfd[i].client_data;
						apr_size_t len_a = pipestate->size-pipestate->offset;
						state = apr_socket_recv(ret_pfd[i].desc.s, pipestate->reader, &len_a);
						pipestate->offset += len_a;
						pipestate->reader += len_a;
						// read buffer to reader
						if ((pipestate->offset >= pipestate->size)||(APR_STATUS_IS_EAGAIN(state)))
						{
							pipestate->offset = pipestate->size;
							PIPE_STATE_TO_COMPLETE(pipestate->state);
							// read complete, move state to complete
						} else if ((APR_STATUS_IS_EOF(state))||(len_a == 0)) {
							apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate };
							pfd.desc.s = ret_pfd[i].desc.s;
							apr_pollset_remove(pollset, &pfd);
							frl_slab_pfree(pipestate);
							apr_socket_close(ret_pfd[i].desc.s);
							// remote error, close connection
							continue;
						}
						switch (pipestate->state)
						{
							case FRL_PIPE_READ_HEADER_COMPLETE:
							{
								// recv header (hash & size)
								pipestate->data.offset = 0;
								pipestate->data.size = pipestate->header.size;
								state = pipe->recv_before(&pipestate->data.buf, &pipestate->data.size);
								if (FRL_PROGRESS_IS_INTERRUPT(state))
								{
									apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate };
									pfd.desc.s = ret_pfd[i].desc.s;
									apr_pollset_remove(pollset, &pfd);
									frl_slab_pfree(pipestate);
									apr_socket_close(ret_pfd[i].desc.s);
									continue;
								}
								pipestate->state = FRL_PIPE_READ_BLOCK_START;
								// start to read block (<= 4092 bytes each)
								pipestate->reader = pipestate->buffer;
								pipestate->offset = 0;
								if (pipestate->data.size < SIZEOF_FRL_PIPE_BLOCK_BUFFER)
									pipestate->size = pipestate->data.size+SIZEOF_FRL_PIPE_HEADER_T;
								else
									pipestate->size = SOCKET_PACKAGE_SIZE;
								break;
							}
							case FRL_PIPE_READ_BLOCK_COMPLETE:
							{
								// a block complete, move to data
								memcpy(pipestate->data.buf+pipestate->data.offset, &pipestate->block.start, pipestate->block.header.size);
								hash = hashlittle(&pipestate->block.start, pipestate->size-SIZEOF_FRL_PIPE_HEADER_T);
								if (hash != pipestate->block.header.hash)
								{
									// check the hash fingerprint of the block
									apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate };
									pfd.desc.s = ret_pfd[i].desc.s;
									apr_pollset_remove(pollset, &pfd);
									frl_slab_pfree(pipestate);
									apr_socket_close(ret_pfd[i].desc.s);
									continue;
								}
								pipestate->data.offset += pipestate->block.header.size;
								if (pipestate->data.offset >= pipestate->data.size)
								{
									// finish read, report state to remote
									apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, pipestate };
									pfd.desc.s = ret_pfd[i].desc.s;
									apr_pollset_remove(pollset, &pfd);
									hash = hashlittle(pipestate->data.buf, pipestate->data.size);
									if (hash != pipestate->header.hash)
									{
										// check hash fingerprint of all data
										frl_slab_pfree(pipestate);
										apr_socket_close(ret_pfd[i].desc.s);
									} else {
										pfd.reqevents = APR_POLLOUT;
										state = pipe->recv_after(pipestate->data.buf, pipestate->data.size);
										if (FRL_PROGRESS_IS_INTERRUPT(state))
										{
											frl_slab_pfree(pipestate);
											apr_socket_close(ret_pfd[i].desc.s);
										} else {
											pipestate->state = FRL_PIPE_SEND_HEADER_START;
											pipestate->reader = (char*)&pipestate->header;
											pipestate->offset = 0;
											pipestate->size = SIZEOF_FRL_PIPE_HEADER_T;
											apr_pollset_add(pollset, &pfd);
										}
									}
									continue;
								}
								// to start read successor block
								pipestate->state = FRL_PIPE_READ_BLOCK_START;
								pipestate->reader = pipestate->buffer;
								pipestate->offset = 0;
								if (pipestate->data.size-pipestate->data.offset < SIZEOF_FRL_PIPE_BLOCK_BUFFER)
									pipestate->size = pipestate->data.size-pipestate->data.offset+SIZEOF_FRL_PIPE_HEADER_T;
								else
									pipestate->size = SOCKET_PACKAGE_SIZE;
								break;
							}
							default:
								break;
						}
					} else if (ret_pfd[i].rtnevents & APR_POLLOUT) {
						// send report information, basic header
						frl_pipe_state_t* pipestate = (frl_pipe_state_t*)ret_pfd[i].client_data;
						apr_size_t len_a = pipestate->size-pipestate->offset;
						state = apr_socket_send(ret_pfd[i].desc.s, pipestate->reader, &len_a);
						pipestate->offset += len_a;
						pipestate->reader += len_a;
						if ((pipestate->offset >= pipestate->size)||(APR_STATUS_IS_EAGAIN(state)))
						{
							pipestate->offset = pipestate->size;
							PIPE_STATE_TO_COMPLETE(pipestate->state);
						} else if ((APR_STATUS_IS_EOF(state))||(len_a == 0)) {
							apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLOUT, 0, { NULL }, pipestate };
							pfd.desc.s = ret_pfd[i].desc.s;
							apr_pollset_remove(pollset, &pfd);
							frl_slab_pfree(pipestate);
							apr_socket_close(ret_pfd[i].desc.s);
							continue;
						}
						switch (pipestate->state)
						{
							case FRL_PIPE_SEND_HEADER_COMPLETE:
							{
								// complete, return to listen state
								apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLOUT, 0, { NULL }, pipestate };
								pfd.desc.s = ret_pfd[i].desc.s;
								apr_pollset_remove(pollset, &pfd);
								pfd.reqevents = APR_POLLIN;
								pipestate->state = FRL_PIPE_DISABLED;
								pipestate->reader = 0;
								pipestate->offset = 0;
								pipestate->size = 0;
								apr_pollset_add(pollset, &pfd);
								break;
							}
							default:
								break;
						}
					} else {
						// other errors, close connection
						frl_pipe_state_t* pipestate = (frl_pipe_state_t*)ret_pfd[i].client_data;
						apr_pollfd_t pfd = { pipe->sockpool, APR_POLL_SOCKET, APR_POLLIN | APR_POLLOUT, 0, { NULL }, pipestate };
						pfd.desc.s = ret_pfd[i].desc.s;
						apr_pollset_remove(pollset, &pfd);
						frl_slab_pfree(pipestate);
						apr_socket_close(ret_pfd[i].desc.s);
					}
				}
			}
		} else if (!APR_STATUS_IS_TIMEUP(pipe->recv_state)) {
Exemplo n.º 22
0
lt_http_status_t lt_http_server_create( lt_http_server_t ** server,
        const char * filepath,
        int port,
        apr_pool_t * pool )
{
    CREATE_POOL_IF_NULL( pool );

    *server = ( lt_http_server_t * ) apr_pcalloc( pool,
            sizeof( lt_http_server_t ) );

    if( *server == NULL ) return LT_HTTP_INVALID_ARG;

    ( *server )->pool = pool;
    ( *server )->port = port;
    ( *server )->filepath = apr_pstrdup( pool, filepath );
    ( *server )->stoprequested = 0;
    ( *server )->thread = NULL;

    /*
     * TODO: extract filename from filepath and urlencode it to
     * create the only url that we support for GET method. I'm leaving it
     * unimplemented for now because it's not that important
     */

    /* determine file size and name */
    if( APR_SUCCESS != apr_stat( &(( *server )->finfo),
                    ( *server )->filepath,
                    APR_FINFO_SIZE,
                    pool ) ) {
        my_perror( "ERROR: apr_stat failed with: " );
        return LT_HTTP_INVALID_ARG;
    }

    /* open file */
    if( APR_SUCCESS != apr_file_open( &(( *server )->file),
                    ( *server )->filepath,
                    APR_READ | APR_BINARY | APR_SENDFILE_ENABLED,
                    0, pool ) ) {
        my_perror( "ERROR: apr_file_open failed with: " );
        return LT_HTTP_INVALID_ARG;
    }

    /* create socket */
    if( APR_SUCCESS != apr_socket_create( &(( *server )->socket),
                    APR_INET, SOCK_STREAM,
#if (APR_MAJOR_VERSION > 0)
                    APR_PROTO_TCP,
#endif
                    pool ) ) {
        my_perror( "ERROR: apr_socket_create failed with: " );
        return LT_HTTP_INVALID_ARG;
    }

    {
        /* prepare socket address */
        apr_sockaddr_t * sa = NULL;
        if( APR_SUCCESS != apr_sockaddr_info_get( &sa,
                        NULL, APR_UNSPEC, port, 0, pool ) ) {
            my_perror( "ERROR: apr_sockaddr_info_get failed with: " );
            return LT_HTTP_INVALID_ARG;
        }

        /* bind socket to given port or let the OS to give us port */
        if( APR_SUCCESS != apr_socket_bind(
                        ( *server )->socket, sa ) ) {
            my_perror( "ERROR: apr_socket_bind failed with: " );
            return LT_HTTP_INVALID_ARG;
        }
    }

    /* determine where we are really listening */
    {
        apr_sockaddr_t * sa = NULL;
        if( APR_SUCCESS != apr_socket_addr_get( &sa,
                        APR_LOCAL, ( *server )->socket ) ) {
            my_perror( "ERROR: apr_socket_addr_get failed with: " );
            return LT_HTTP_INVALID_ARG;
        }

        ( *server )->port = sa->port;
    }

    /* and make the socket listen */
    if( APR_SUCCESS != apr_socket_listen(
                    ( *server )->socket, 5 ) ) {
        my_perror( "ERROR: apr_socket_listen failed with: " );
        return LT_HTTP_INVALID_ARG;
    }

    return LT_HTTP_SUCCESS;
}
Exemplo n.º 23
0
int main(int argc, const char * const argv[])
{
    apr_file_t *infd, *skwrapper;
    apr_sockaddr_t *skaddr;
    apr_getopt_t *gopt;
    apr_socket_t *skt;
    apr_pool_t *pool;
    apr_status_t rv;
    apr_proc_t proc;


    /* Command line arguments */
    int num_to_start = 1, port = 0;
    const char *interface = NULL;
    const char *command = NULL;

    apr_app_initialize(&argc, &argv, NULL);

    atexit(apr_terminate);

    apr_pool_create(&pool, NULL);

    rv = apr_getopt_init(&gopt, pool, argc, argv);
    if (rv) {
        return EXIT_FAILURE;
    }

    for (;;) {
        const char *arg;
        char opt;

        rv = apr_getopt(gopt, "c:p:i:N:", &opt, &arg);
        if (APR_STATUS_IS_EOF(rv)) {
            break;
        } else if (rv) {
            usage();
        } else {
            switch (opt) {
            case 'c':
                command = arg;
                break;

            case 'p':
                port = atoi(arg);
                if (! port) {
                    usage();
                }
                break;

            case 'i':
                interface = arg;
                break;

            case 'N':
                num_to_start = atoi(arg);
                if (! num_to_start) {
                    usage();
                }
                break;

            default:
                break;
            }
        }
    }

    if (! command || ! port) {
        usage();
    }

    rv = apr_sockaddr_info_get(&skaddr, interface, APR_UNSPEC, port, 0, pool);
    if (rv) {
        exit_error(rv, "apr_sockaddr_info_get");
    }

    rv = apr_socket_create(&skt, skaddr->family, SOCK_STREAM, APR_PROTO_TCP, pool);
    if (rv) {
        exit_error(rv, "apr_socket_create");
    }

    rv = apr_socket_bind(skt, skaddr);
    if (rv) {
        exit_error(rv, "apr_socket_bind");
    }

    rv = apr_socket_listen(skt, 1024);
    if (rv) {
        exit_error(rv, "apr_socket_listen");
    }

    rv = apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
    if (rv) {
        exit_error(rv, "apr_proc_detach");
    }

#if defined(WIN32) || defined(OS2) || defined(NETWARE)

#error "Please implement me."

#else

    while (--num_to_start >= 0) {
        rv = apr_proc_fork(&proc, pool);
        if (rv == APR_INCHILD) {
            apr_os_file_t oft = 0;
            apr_os_sock_t oskt;

            /* Ok, so we need a file that has file descriptor 0 (which
             * FastCGI wants), but points to our socket.  This isn't really
             * possible in APR, so we cheat a bit.  I have no idea how to
             * do this on a non-unix platform, so for now this is platform
             * specific.  Ick.
             *
             * Note that this has to happen post-detach, otherwise fd 0
             * gets closed during apr_proc_detach and it's all for nothing.
             *
             * Unfortunately, doing this post detach means we have no way
             * to let anyone know if there's a problem at this point :( */

            rv = apr_os_file_put(&infd, &oft, APR_READ | APR_WRITE, pool);
            if (rv) {
                exit(EXIT_FAILURE);
            }

            rv = apr_os_sock_get(&oskt, skt);
            if (rv) {
                exit(EXIT_FAILURE);
            }

            rv = apr_os_file_put(&skwrapper, &oskt, APR_READ | APR_WRITE,
                                 pool);
            if (rv) {
                exit(EXIT_FAILURE);
            }

            rv = apr_file_dup2(infd, skwrapper, pool);
            if (rv) {
                exit(EXIT_FAILURE);
            }

            /* XXX Can't use apr_proc_create because there's no way to get
             *     infd into the procattr without going through another dup2,
             *     which means by the time it gets to the fastcgi process it
             *     is no longer fd 0, so it doesn't work.  Sigh. */

            execl(command, command, NULL);

        } else if (rv == APR_INPARENT) {
            if (num_to_start == 0) {
                apr_socket_close(skt);
            }
        } else {
            exit_error(rv, "apr_proc_fork");
        }
    }

#endif

    return EXIT_SUCCESS;
}
Exemplo n.º 24
0
static apr_status_t socket_pipe_create(apr_socket_t **rd, apr_socket_t **wr, apr_pool_t *pool)
{
	static int id = 0;

	apr_socket_t *ls = NULL;
	apr_sockaddr_t *pa = NULL;
	apr_sockaddr_t *ca = NULL;
	apr_size_t nrd;
	int uid[2];
	int iid[2];

	/* Create the unique socket identifier
	 * so that we know the connection originated
	 * from us.
	 */
	uid[0] = getpid();
	uid[1] = id++;
	if(apr_socket_create(&ls, AF_INET, SOCK_STREAM, APR_PROTO_TCP, pool) != APR_SUCCESS) {
		return apr_get_netos_error();
	}
	apr_socket_opt_set(ls, APR_SO_REUSEADDR, 1);

	if(apr_sockaddr_info_get(&pa,"127.0.0.1",APR_INET,0,0,pool) != APR_SUCCESS) {
		apr_socket_close(ls);
		return apr_get_netos_error();
	}

	if(apr_socket_bind(ls, pa) != APR_SUCCESS) {
		apr_socket_close(ls);
		return apr_get_netos_error();
	}
	
	if(apr_socket_addr_get(&ca,APR_LOCAL,ls) != APR_SUCCESS) {
		apr_socket_close(ls);
		return apr_get_netos_error();
	}

	if(apr_socket_listen(ls,1) != APR_SUCCESS) {
		apr_socket_close(ls);
		return apr_get_netos_error();
	}

	if(apr_socket_create(wr, AF_INET, SOCK_STREAM, APR_PROTO_TCP, pool) != APR_SUCCESS) {
		apr_socket_close(ls);
		return apr_get_netos_error();
	}
	apr_socket_opt_set(*wr, APR_SO_REUSEADDR, 1);

	if(apr_socket_connect(*wr, ca) != APR_SUCCESS) {
		apr_socket_close(ls);
		apr_socket_close(*wr);
		return apr_get_netos_error();
	}
	nrd = sizeof(uid);
	if(apr_socket_send(*wr, (char *)uid, &nrd) != APR_SUCCESS) {
		apr_socket_close(ls);
		apr_socket_close(*wr);
		return apr_get_netos_error();
	}
	
	apr_socket_opt_set(ls, APR_SO_NONBLOCK, 0);
	/* Listening socket is blocking by now. The accept should 
	 * return immediatelly because we connected already.
	 */
	if(apr_socket_accept(rd, ls, pool) != APR_SUCCESS) {
		apr_socket_close(ls);
		apr_socket_close(*wr);
		return apr_get_netos_error();
	}

	/* Put read side of the pipe to the blocking mode */
	apr_socket_opt_set(*rd, APR_SO_NONBLOCK, 0);

	for (;;) {
		/* Verify the connection by reading the sent identification */
		nrd = sizeof(iid);
		if(apr_socket_recv(*rd, (char *)iid, &nrd) != APR_SUCCESS) {
			apr_socket_close(ls);
			apr_socket_close(*wr);
			apr_socket_close(*rd);
			return apr_get_netos_error();
		}
		if(nrd == sizeof(iid)) {
			if(memcmp(uid, iid, sizeof(uid)) == 0) {
				/* Wow, we recived what we sent */
				break;
			}
		}
	}

	/* We don't need the listening socket any more */
	apr_socket_close(ls);
	return APR_SUCCESS;
}
Exemplo n.º 25
0
SWITCH_DECLARE(switch_status_t) switch_socket_listen(switch_socket_t *sock, int32_t backlog)
{
	return apr_socket_listen(sock, backlog);
}
Exemplo n.º 26
0
static void create_listen_socket(apr_socket_t**plisten_sock, apr_pool_t*mp)
{
	apr_status_t	rc;
	apr_socket_t	*listen_sock;
	apr_sockaddr_t	*saddr;

	*plisten_sock = NULL;

	/*
	 * Get a list of addresses for this HOST:PORT
	 */
	rc = apr_sockaddr_info_get(&saddr, lfd_config_listen_host, APR_UNSPEC, lfd_config_listen_port, 0, mp);
	if (APR_SUCCESS != rc)
	{
		lfd_log_apr_err(rc, "apr_sockaddr_info_get failed");
		return;
	}
	if (NULL == saddr)
	{
		lfd_log(LFD_ERROR, "apr_sockaddr_info_get returned NO entries");
		return;
	}

	/*
	 * iterate through all address info descriptors for this host
	 * until you find one that you can bind on, or until there are
	 * no more addresses to try.
	 */
	do {
		// create a socket
		rc = apr_socket_create(&listen_sock, saddr->family, SOCK_STREAM, APR_PROTO_TCP, mp);
		if(APR_SUCCESS != rc)
		{
			lfd_log_apr_err(rc, "apr_socket_create failed");
			listen_sock = NULL;
			goto try_next_addr;
		}

		// bind it - we don't really care if REUSEADDR fails or not
		apr_socket_opt_set(listen_sock, APR_SO_REUSEADDR, 1);
		rc = apr_socket_bind(listen_sock, saddr);
		if(APR_SUCCESS != rc)
		{
			lfd_log_apr_err(rc, "apr_socket_bind failed");
			apr_socket_close(listen_sock);
			listen_sock = NULL;
			goto try_next_addr;
		}

		// and listen on it
		rc = apr_socket_listen(listen_sock, lfd_config_backlog);
		if(APR_SUCCESS != rc) {
			lfd_log_apr_err(rc, "apr_socket_listen failed");
			apr_socket_close(listen_sock);
			listen_sock = NULL;
			goto try_next_addr;
		}

try_next_addr:
		saddr = saddr->next;
	} while((NULL == listen_sock) && (NULL != saddr));

	/* if one iteration finished succcessfully listen_sock will be non-NULL.
	 * if none finish successfully, listen_sock will be NULL
	 */
	*plisten_sock = listen_sock;
}
Exemplo n.º 27
0
int main(int argc, char *argv[])
{
	char errbuf[ERRBUFLEN + 1];
	apr_pool_t *pool;
	apr_proc_t proc;
	dynalogin_session_t *h;
	apr_status_t res;

	apr_sockaddr_t *sa;
	apr_socket_t *socket, *socket_new;

	char *cfg_filename;
	char *bind_address;
	int bind_port;
	int qlen = 32;
	int cfg_detach = 1;
	int ret;

	int done = 0;

	apr_hash_t *config;

	if(apr_initialize() != APR_SUCCESS)
	{
		fprintf(stderr, "apr_initialize failed\n");
		return 1;
	}

	/* Just return an error if a client closes a socket */
	apr_signal_block(SIGPIPE);

	openlog(argv[0], LOG_PID, LOG_AUTHPRIV);

	if((res = apr_pool_create(&pool, NULL)) != APR_SUCCESS)
	{
		syslog(LOG_ERR, "failed to create root pool: %s",
				apr_strerror(res, errbuf, ERRBUFLEN));
		return 1;
	}

	if(argc == 2)
		cfg_filename = argv[1];
	else
		cfg_filename = apr_psprintf(pool, "%s%c%s",
			SYSCONFDIR, DIR_SEP, DEFAULT_CONFIG_FILENAME);
	if(cfg_filename == NULL)
	{
		syslog(LOG_ERR, "apr_psprintf failed to create filename: %s",
				apr_strerror(res, errbuf, ERRBUFLEN));
		return 1;
	}
	/* Read config */
	if(dynalogin_read_config_from_file(&config, cfg_filename, pool)
			!= DYNALOGIN_SUCCESS)
	{
		syslog(LOG_ERR, "failed to read config file %s",
				cfg_filename);
		return 1;
	}

	/* Set up DYNALOGIN session (threadsafe?) */
	if(dynalogin_init(&h, pool, config) != DYNALOGIN_SUCCESS)
	{
		syslog(LOG_ERR, "failed to init dynalogin stack");
		return 1;
	}

	/* Daemonize? */
	GET_INT_PARAM(cfg_detach, config, DYNALOGIND_PARAM_DETACH)
	if((res=apr_proc_detach(cfg_detach)) != APR_SUCCESS)
	{
		syslog(LOG_ERR, "failed to detach: %s",
				apr_strerror(res, errbuf, ERRBUFLEN));
		return 1;
	}

	/* Create socket for clients */
	if((res=apr_socket_create(&socket,
			APR_INET, SOCK_STREAM, APR_PROTO_TCP, pool))!=APR_SUCCESS)
	{
		syslog(LOG_ERR, "failed to create listening socket: %s",
				apr_strerror(res, errbuf, ERRBUFLEN));
		return 1;
	}
	GET_STRING_PARAM_DEF(bind_address, config, DYNALOGIND_PARAM_BIND_ADDR, DEFAULT_BIND_ADDR)
	GET_INT_PARAM_DEF(bind_port, config, DYNALOGIND_PARAM_BIND_PORT, DEFAULT_BIND_PORT)
	if((res=apr_sockaddr_info_get(&sa, bind_address, APR_UNSPEC,
			bind_port, APR_IPV4_ADDR_OK || APR_IPV6_ADDR_OK, pool))!=APR_SUCCESS)
	{
		syslog(LOG_ERR, "failed to resolve bind address: %s",
				apr_strerror(res, errbuf, ERRBUFLEN));
		apr_socket_close(socket);
		return 1;
	}
	if((res=apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1))!=APR_SUCCESS)
	{
		syslog(LOG_ERR, "failed to set APR_SO_REUSEADDR: %s",
			apr_strerror(res, errbuf, ERRBUFLEN));
		apr_socket_close(socket);
		return 1;
	}
	if((res=apr_socket_bind(socket, sa))!=APR_SUCCESS)
	{
		syslog(LOG_ERR, "failed to bind: %s",
				apr_strerror(res, errbuf, ERRBUFLEN));
		apr_socket_close(socket);
		return 1;
	}

	GET_STRING_PARAM_DEF(tls_cert, config, DYNALOGIND_PARAM_TLS_CERT, NULL)
	GET_STRING_PARAM_DEF(tls_key, config, DYNALOGIND_PARAM_TLS_KEY, NULL)
	if(tls_cert != NULL)
	{
		if(tls_key == NULL)
		{
			syslog(LOG_ERR, "%s specified, but %s not specified", DYNALOGIND_PARAM_TLS_CERT,
					DYNALOGIND_PARAM_TLS_KEY);
			return 1;
		}

		gnutls_global_init ();

		gnutls_certificate_allocate_credentials (&x509_cred);

		ret = gnutls_certificate_set_x509_key_file (x509_cred, tls_cert, tls_key,
				GNUTLS_X509_FMT_PEM);
		if (ret < 0)
		{
			syslog(LOG_ERR, "No certificate or key were found");
			return 1;
		}

		generate_dh_params ();

		gnutls_priority_init (&priority_cache, "PERFORMANCE:%SERVER_PRECEDENCE", NULL);

		gnutls_certificate_set_dh_params (x509_cred, dh_params);
	}
	else if(tls_key == NULL)
	{
		syslog(LOG_ERR, "%s specified, but %s not specified", DYNALOGIND_PARAM_TLS_KEY,
				DYNALOGIND_PARAM_TLS_CERT);
		return 1;
	}

	/* Main loop */
	while(done != 1)
	{
		if((res=apr_socket_listen(socket, qlen))!=APR_SUCCESS)
		{
			syslog(LOG_ERR, "failed apr_socket_listen: %s",
					apr_strerror(res, errbuf, ERRBUFLEN));
			apr_socket_close(socket);
			return 1;
		}

		if((res=apr_socket_accept(&socket_new, socket, pool))!=APR_SUCCESS)
		{
			syslog(LOG_ERR, "failed to accept incoming connection: %s",
					apr_strerror(res, errbuf, ERRBUFLEN));
			apr_socket_close(socket);
			return 1;
		}
		syslog(LOG_INFO, "new incoming connection");
		if((res=handle_new_client(socket_new, pool, h))!=APR_SUCCESS)
		{
			syslog(LOG_ERR, "failed to handle incoming connection: %s",
					apr_strerror(res, errbuf, ERRBUFLEN));
			apr_socket_close(socket);
			return 1;
		}
	}
	apr_socket_close(socket);
	return 0;
}
void LLPluginProcessParent::idle(void)
{
    bool idle_again;

    do
    {
        // process queued messages
        mIncomingQueueMutex.lock();
        while(!mIncomingQueue.empty())
        {
            LLPluginMessage message = mIncomingQueue.front();
            mIncomingQueue.pop();
            mIncomingQueueMutex.unlock();

            receiveMessage(message);

            mIncomingQueueMutex.lock();
        }

        mIncomingQueueMutex.unlock();

        // Give time to network processing
        if(mMessagePipe)
        {
            // Drain any queued outgoing messages
            mMessagePipe->pumpOutput();

            // Only do input processing here if this instance isn't in a pollset.
            if(!mPolledInput)
            {
                mMessagePipe->pumpInput();
            }
        }

        if(mState <= STATE_RUNNING)
        {
            if(APR_STATUS_IS_EOF(mSocketError))
            {
                // Plugin socket was closed.  This covers both normal plugin termination and plugin crashes.
                errorState();
            }
            else if(mSocketError != APR_SUCCESS)
            {
                // The socket is in an error state -- the plugin is gone.
                LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
                errorState();
            }
        }

        // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
        // USE THIS CAREFULLY, since it can starve other code.  Specifically make sure there's no way to get into a closed cycle and never return.
        // When in doubt, don't do it.
        idle_again = false;
        switch(mState)
        {
        case STATE_UNINITIALIZED:
            break;

        case STATE_INITIALIZED:
        {

            apr_status_t status = APR_SUCCESS;
            apr_sockaddr_t* addr = NULL;
            mListenSocket = LLSocket::create(LLSocket::STREAM_TCP);
            mBoundPort = 0;

            // This code is based on parts of LLSocket::create() in lliosocket.cpp.

            status = apr_sockaddr_info_get(
                         &addr,
                         "127.0.0.1",
                         APR_INET,
                         0,	// port 0 = ephemeral ("find me a port")
                         0,
                         AIAPRRootPool::get()());

            if(ll_apr_warn_status(status))
            {
                killSockets();
                errorState();
                break;
            }

            // This allows us to reuse the address on quick down/up. This is unlikely to create problems.
            ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1));

            status = apr_socket_bind(mListenSocket->getSocket(), addr);
            if(ll_apr_warn_status(status))
            {
                killSockets();
                errorState();
                break;
            }

            // Get the actual port the socket was bound to
            {
                apr_sockaddr_t* bound_addr = NULL;
                if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket())))
                {
                    killSockets();
                    errorState();
                    break;
                }
                mBoundPort = bound_addr->port;

                if(mBoundPort == 0)
                {
                    LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL;

                    killSockets();
                    errorState();
                    break;
                }
            }

            LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL;

            // Make the listen socket non-blocking
            status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1);
            if(ll_apr_warn_status(status))
            {
                killSockets();
                errorState();
                break;
            }

            apr_socket_timeout_set(mListenSocket->getSocket(), 0);
            if(ll_apr_warn_status(status))
            {
                killSockets();
                errorState();
                break;
            }

            // If it's a stream based socket, we need to tell the OS
            // to keep a queue of incoming connections for ACCEPT.
            status = apr_socket_listen(
                         mListenSocket->getSocket(),
                         10); // FIXME: Magic number for queue size

            if(ll_apr_warn_status(status))
            {
                killSockets();
                errorState();
                break;
            }

            // If we got here, we're listening.
            setState(STATE_LISTENING);
        }
        break;

        case STATE_LISTENING:
        {
            // Launch the plugin process.

            // Only argument to the launcher is the port number we're listening on
            std::stringstream stream;
            stream << mBoundPort;
            mProcess.addArgument(stream.str());
            if(mProcess.launch() != 0)
            {
                errorState();
            }
            else
            {
                if(mDebug)
                {
                    // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
                    std::stringstream cmd;

#if LL_DARWIN
                    // The command we're constructing would look like this on the command line:
                    // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
                    mDebugger.setExecutable("/usr/bin/osascript");
                    mDebugger.addArgument("-e");
                    mDebugger.addArgument("tell application \"Terminal\"");
                    mDebugger.addArgument("-e");
                    cmd << "set win to do script \"gdb -pid " << mProcess.getProcessID() << "\"";
                    mDebugger.addArgument(cmd.str());
                    mDebugger.addArgument("-e");
                    mDebugger.addArgument("do script \"continue\" in win");
                    mDebugger.addArgument("-e");
                    mDebugger.addArgument("end tell");
                    mDebugger.launch();
#elif LL_LINUX
                    // The command we're constructing would look like this on the command line:
                    // /usr/bin/xterm -geometry 160x24-0+0 -e '/usr/bin/gdb -n /proc/12345/exe 12345'
                    // This can be changed by setting the following environment variables, for example:
                    // export LL_DEBUG_TERMINAL_COMMAND="/usr/bin/gnome-terminal --geometry=165x24-0+0 -e %s"
                    // export LL_DEBUG_GDB_PATH=/usr/bin/gdb
                    char const* env;
                    std::string const terminal_command = (env = getenv("LL_DEBUG_TERMINAL_COMMAND")) ? env : "/usr/bin/xterm -geometry 160x24+0+0 -e %s";
                    char const* const gdb_path = (env = getenv("LL_DEBUG_GDB_PATH")) ? env : "/usr/bin/gdb";
                    cmd << gdb_path << " -n /proc/" << mProcess.getProcessID() << "/exe " << mProcess.getProcessID();

                    typedef boost::tokenizer< boost::escaped_list_separator<
                    char>, typename std::basic_string<
                    char>::const_iterator,
                         std::basic_string<char> >  tokenizerT;

                    tokenizerT tok(terminal_command.begin(),
                                   terminal_command.end(),
                                   boost::escaped_list_separator< char >("\\",
                                           " ", "'\""));
                    std::vector< std::basic_string<char> > tokens;
                    for (typename tokenizerT::iterator
                            cur_token(tok.begin()), end_token(tok.end());
                            cur_token != end_token; ++cur_token) {
                        if (!cur_token->empty())
                            tokens.push_back(*cur_token);
                    }
                    std::vector<std::string>::iterator token = tokens.begin();
                    mDebugger.setExecutable(*token);
                    while (++token != tokens.end())
                    {
                        if (*token == "%s")
                        {
                            mDebugger.addArgument(cmd.str());
                        }
                        else
                        {
                            mDebugger.addArgument(*token);
                        }
                    }
                    mDebugger.launch();
#endif
                }

                // This will allow us to time out if the process never starts.
                mHeartbeat.start();
                mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
                setState(STATE_LAUNCHED);
            }
        }
        break;

        case STATE_LAUNCHED:
            // waiting for the plugin to connect
            if(pluginLockedUpOrQuit())
            {
                errorState();
            }
            else
            {
                // Check for the incoming connection.
                if(accept())
                {
                    // Stop listening on the server port
                    mListenSocket.reset();
                    setState(STATE_CONNECTED);
                }
            }
            break;

        case STATE_CONNECTED:
            // waiting for hello message from the plugin

            if(pluginLockedUpOrQuit())
            {
                errorState();
            }
            break;

        case STATE_HELLO:
            LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL;

            // Send the message to load the plugin
            {
                LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin");
                message.setValue("file", mPluginFile);
                sendMessage(message);
            }

            setState(STATE_LOADING);
            break;

        case STATE_LOADING:
            // The load_plugin_response message will kick us from here into STATE_RUNNING
            if(pluginLockedUpOrQuit())
            {
                errorState();
            }
            break;

        case STATE_RUNNING:
            if(pluginLockedUpOrQuit())
            {
                errorState();
            }
            break;

        case STATE_EXITING:
            if(!mProcess.isRunning())
            {
                setState(STATE_CLEANUP);
            }
            else if(pluginLockedUp())
            {
                LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL;
                errorState();
            }
            break;

        case STATE_LAUNCH_FAILURE:
            if(mOwner != NULL)
            {
                mOwner->pluginLaunchFailed();
            }
            setState(STATE_CLEANUP);
            break;

        case STATE_ERROR:
            if(mOwner != NULL)
            {
                mOwner->pluginDied();
            }
            setState(STATE_CLEANUP);
            break;

        case STATE_CLEANUP:
            mProcess.kill();
            killSockets();
            setState(STATE_DONE);
            break;


        case STATE_DONE:
            // just sit here.
            break;

        }

    } while (idle_again);
}
Exemplo n.º 29
0
// static
LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
{
	LLMemType m1(LLMemType::MTYPE_IO_TCP);
	LLSocket::ptr_t rv;
	apr_socket_t* socket = NULL;
	apr_pool_t* new_pool = NULL;
	apr_status_t status = APR_EGENERAL;

	// create a pool for the socket
	status = apr_pool_create(&new_pool, pool);
	if(ll_apr_warn_status(status))
	{
		if(new_pool) apr_pool_destroy(new_pool);
		return rv;
	}

	if(STREAM_TCP == type)
	{
		status = apr_socket_create(
			&socket,
			APR_INET,
			SOCK_STREAM,
			APR_PROTO_TCP,
			new_pool);
	}
	else if(DATAGRAM_UDP == type)
	{
		status = apr_socket_create(
			&socket,
			APR_INET,
			SOCK_DGRAM,
			APR_PROTO_UDP,
			new_pool);
	}
	else
	{
		if(new_pool) apr_pool_destroy(new_pool);
		return rv;
	}
	if(ll_apr_warn_status(status))
	{
		if(new_pool) apr_pool_destroy(new_pool);
		return rv;
	}
	rv = ptr_t(new LLSocket(socket, new_pool));
	if(port > 0)
	{
		apr_sockaddr_t* sa = NULL;
		status = apr_sockaddr_info_get(
			&sa,
			APR_ANYADDR,
			APR_UNSPEC,
			port,
			0,
			new_pool);
		if(ll_apr_warn_status(status))
		{
			rv.reset();
			return rv;
		}
		// This allows us to reuse the address on quick down/up. This
		// is unlikely to create problems.
		ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1));
		status = apr_socket_bind(socket, sa);
		if(ll_apr_warn_status(status))
		{
			rv.reset();
			return rv;
		}
		lldebugs << "Bound " << ((DATAGRAM_UDP == type) ? "udp" : "tcp")
				 << " socket to port: " << sa->port << llendl;
		if(STREAM_TCP == type)
		{
			// If it's a stream based socket, we need to tell the OS
			// to keep a queue of incoming connections for ACCEPT.
			lldebugs << "Setting listen state for socket." << llendl;
			status = apr_socket_listen(
				socket,
				LL_DEFAULT_LISTEN_BACKLOG);
			if(ll_apr_warn_status(status))
			{
				rv.reset();
				return rv;
			}
		}
	}
	else
	{
		// we need to indicate that we have an ephemeral port if the
		// previous calls were successful. It will
		port = PORT_EPHEMERAL;
	}
	rv->mPort = port;
	rv->setOptions();
	return rv;
}
Exemplo n.º 30
0
/*
 * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
 * either return an error to be displayed, or set *EXIT_CODE to non-zero and
 * return SVN_NO_ERROR.
 */
static svn_error_t *
sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
{
  enum run_mode run_mode = run_mode_unspecified;
  svn_boolean_t foreground = FALSE;
  apr_socket_t *sock;
  apr_sockaddr_t *sa;
  svn_error_t *err;
  apr_getopt_t *os;
  int opt;
  serve_params_t params;
  const char *arg;
  apr_status_t status;
#ifndef WIN32
  apr_proc_t proc;
#endif
  svn_boolean_t is_multi_threaded;
  enum connection_handling_mode handling_mode = CONNECTION_DEFAULT;
  svn_boolean_t cache_fulltexts = TRUE;
  svn_boolean_t cache_txdeltas = TRUE;
  svn_boolean_t cache_revprops = FALSE;
  svn_boolean_t use_block_read = FALSE;
  apr_uint16_t port = SVN_RA_SVN_PORT;
  const char *host = NULL;
  int family = APR_INET;
  apr_int32_t sockaddr_info_flags = 0;
#if APR_HAVE_IPV6
  svn_boolean_t prefer_v6 = FALSE;
#endif
  svn_boolean_t quiet = FALSE;
  svn_boolean_t is_version = FALSE;
  int mode_opt_count = 0;
  int handling_opt_count = 0;
  const char *config_filename = NULL;
  const char *pid_filename = NULL;
  const char *log_filename = NULL;
  svn_node_kind_t kind;
  apr_size_t min_thread_count = THREADPOOL_MIN_SIZE;
  apr_size_t max_thread_count = THREADPOOL_MAX_SIZE;
#ifdef SVN_HAVE_SASL
  SVN_ERR(cyrus_init(pool));
#endif

  /* Check library versions */
  SVN_ERR(check_lib_versions());

  /* Initialize the FS library. */
  SVN_ERR(svn_fs_initialize(pool));

  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));

  params.root = "/";
  params.tunnel = FALSE;
  params.tunnel_user = NULL;
  params.read_only = FALSE;
  params.base = NULL;
  params.cfg = NULL;
  params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
  params.logger = NULL;
  params.config_pool = NULL;
  params.authz_pool = NULL;
  params.fs_config = NULL;
  params.vhost = FALSE;
  params.username_case = CASE_ASIS;
  params.memory_cache_size = (apr_uint64_t)-1;
  params.zero_copy_limit = 0;
  params.error_check_interval = 4096;

  while (1)
    {
      status = apr_getopt_long(os, svnserve__options, &opt, &arg);
      if (APR_STATUS_IS_EOF(status))
        break;
      if (status != APR_SUCCESS)
        {
          usage(argv[0], pool);
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }
      switch (opt)
        {
        case '6':
#if APR_HAVE_IPV6
          prefer_v6 = TRUE;
#endif
          /* ### Maybe error here if we don't have IPV6 support? */
          break;

        case 'h':
          help(pool);
          return SVN_NO_ERROR;

        case 'q':
          quiet = TRUE;
          break;

        case SVNSERVE_OPT_VERSION:
          is_version = TRUE;
          break;

        case 'd':
          if (run_mode != run_mode_daemon)
            {
              run_mode = run_mode_daemon;
              mode_opt_count++;
            }
          break;

        case SVNSERVE_OPT_FOREGROUND:
          foreground = TRUE;
          break;

        case SVNSERVE_OPT_SINGLE_CONN:
          handling_mode = connection_mode_single;
          handling_opt_count++;
          break;

        case 'i':
          if (run_mode != run_mode_inetd)
            {
              run_mode = run_mode_inetd;
              mode_opt_count++;
            }
          break;

        case SVNSERVE_OPT_LISTEN_PORT:
          {
            apr_uint64_t val;

            err = svn_cstring_strtoui64(&val, arg, 0, APR_UINT16_MAX, 10);
            if (err)
              return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
                                       _("Invalid port '%s'"), arg);
            port = (apr_uint16_t)val;
          }
          break;

        case SVNSERVE_OPT_LISTEN_HOST:
          host = arg;
          break;

        case 't':
          if (run_mode != run_mode_tunnel)
            {
              run_mode = run_mode_tunnel;
              mode_opt_count++;
            }
          break;

        case SVNSERVE_OPT_TUNNEL_USER:
          params.tunnel_user = arg;
          break;

        case 'X':
          if (run_mode != run_mode_listen_once)
            {
              run_mode = run_mode_listen_once;
              mode_opt_count++;
            }
          break;

        case 'r':
          SVN_ERR(svn_utf_cstring_to_utf8(&params.root, arg, pool));

          SVN_ERR(svn_io_check_resolved_path(params.root, &kind, pool));
          if (kind != svn_node_dir)
            {
              return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                       _("Root path '%s' does not exist "
                         "or is not a directory"), params.root);
            }

          params.root = svn_dirent_internal_style(params.root, pool);
          SVN_ERR(svn_dirent_get_absolute(&params.root, params.root, pool));
          break;

        case 'R':
          params.read_only = TRUE;
          break;

        case 'T':
          handling_mode = connection_mode_thread;
          handling_opt_count++;
          break;

        case 'c':
          params.compression_level = atoi(arg);
          if (params.compression_level < SVN_DELTA_COMPRESSION_LEVEL_NONE)
            params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
          if (params.compression_level > SVN_DELTA_COMPRESSION_LEVEL_MAX)
            params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_MAX;
          break;

        case 'M':
          params.memory_cache_size = 0x100000 * apr_strtoi64(arg, NULL, 0);
          break;

        case SVNSERVE_OPT_CACHE_TXDELTAS:
          cache_txdeltas = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_CACHE_FULLTEXTS:
          cache_fulltexts = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_CACHE_REVPROPS:
          cache_revprops = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_BLOCK_READ:
          use_block_read = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_CLIENT_SPEED:
          {
            apr_size_t bandwidth = (apr_size_t)apr_strtoi64(arg, NULL, 0);

            /* for slower clients, don't try anything fancy */
            if (bandwidth >= 1000)
              {
                /* block other clients for at most 1 ms (at full bandwidth).
                   Note that the send buffer is 16kB anyways. */
                params.zero_copy_limit = bandwidth * 120;

                /* check for aborted connections at the same rate */
                params.error_check_interval = bandwidth * 120;
              }
          }
          break;

        case SVNSERVE_OPT_MIN_THREADS:
          min_thread_count = (apr_size_t)apr_strtoi64(arg, NULL, 0);
          break;

        case SVNSERVE_OPT_MAX_THREADS:
          max_thread_count = (apr_size_t)apr_strtoi64(arg, NULL, 0);
          break;

#ifdef WIN32
        case SVNSERVE_OPT_SERVICE:
          if (run_mode != run_mode_service)
            {
              run_mode = run_mode_service;
              mode_opt_count++;
            }
          break;
#endif

        case SVNSERVE_OPT_CONFIG_FILE:
          SVN_ERR(svn_utf_cstring_to_utf8(&config_filename, arg, pool));
          config_filename = svn_dirent_internal_style(config_filename, pool);
          SVN_ERR(svn_dirent_get_absolute(&config_filename, config_filename,
                                          pool));
          break;

        case SVNSERVE_OPT_PID_FILE:
          SVN_ERR(svn_utf_cstring_to_utf8(&pid_filename, arg, pool));
          pid_filename = svn_dirent_internal_style(pid_filename, pool);
          SVN_ERR(svn_dirent_get_absolute(&pid_filename, pid_filename, pool));
          break;

         case SVNSERVE_OPT_VIRTUAL_HOST:
           params.vhost = TRUE;
           break;

         case SVNSERVE_OPT_LOG_FILE:
          SVN_ERR(svn_utf_cstring_to_utf8(&log_filename, arg, pool));
          log_filename = svn_dirent_internal_style(log_filename, pool);
          SVN_ERR(svn_dirent_get_absolute(&log_filename, log_filename, pool));
          break;

        }
    }

  if (is_version)
    {
      SVN_ERR(version(quiet, pool));
      return SVN_NO_ERROR;
    }

  if (os->ind != argc)
    {
      usage(argv[0], pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  if (mode_opt_count != 1)
    {
      svn_error_clear(svn_cmdline_fputs(
#ifdef WIN32
                      _("You must specify exactly one of -d, -i, -t, "
                        "--service or -X.\n"),
#else
                      _("You must specify exactly one of -d, -i, -t or -X.\n"),
#endif
                       stderr, pool));
      usage(argv[0], pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  if (handling_opt_count > 1)
    {
      svn_error_clear(svn_cmdline_fputs(
                      _("You may only specify one of -T or --single-thread\n"),
                      stderr, pool));
      usage(argv[0], pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  /* construct object pools */
  is_multi_threaded = handling_mode == connection_mode_thread;
  params.fs_config = apr_hash_make(pool);
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS,
                cache_txdeltas ? "1" :"0");
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
                cache_fulltexts ? "1" :"0");
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
                cache_revprops ? "2" :"0");
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
                use_block_read ? "1" :"0");

  SVN_ERR(svn_repos__config_pool_create(&params.config_pool,
                                        is_multi_threaded,
                                        pool));
  SVN_ERR(svn_repos__authz_pool_create(&params.authz_pool,
                                       params.config_pool,
                                       is_multi_threaded,
                                       pool));

  /* If a configuration file is specified, load it and any referenced
   * password and authorization files. */
  if (config_filename)
    {
      params.base = svn_dirent_dirname(config_filename, pool);

      SVN_ERR(svn_repos__config_pool_get(&params.cfg, NULL,
                                         params.config_pool,
                                         config_filename,
                                         TRUE, /* must_exist */
                                         FALSE, /* names_case_sensitive */
                                         NULL,
                                         pool));
    }

  if (log_filename)
    SVN_ERR(logger__create(&params.logger, log_filename, pool));
  else if (run_mode == run_mode_listen_once)
    SVN_ERR(logger__create_for_stderr(&params.logger, pool));

  if (params.tunnel_user && run_mode != run_mode_tunnel)
    {
      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
               _("Option --tunnel-user is only valid in tunnel mode"));
    }

  if (run_mode == run_mode_inetd || run_mode == run_mode_tunnel)
    {
      apr_pool_t *connection_pool;
      svn_ra_svn_conn_t *conn;
      svn_stream_t *stdin_stream;
      svn_stream_t *stdout_stream;

      params.tunnel = (run_mode == run_mode_tunnel);
      apr_pool_cleanup_register(pool, pool, apr_pool_cleanup_null,
                                redirect_stdout);

      SVN_ERR(svn_stream_for_stdin(&stdin_stream, pool));
      SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));

      /* Use a subpool for the connection to ensure that if SASL is used
       * the pool cleanup handlers that call sasl_dispose() (connection_pool)
       * and sasl_done() (pool) are run in the right order. See issue #3664. */
      connection_pool = svn_pool_create(pool);
      conn = svn_ra_svn_create_conn4(NULL, stdin_stream, stdout_stream,
                                     params.compression_level,
                                     params.zero_copy_limit,
                                     params.error_check_interval,
                                     connection_pool);
      err = serve(conn, &params, connection_pool);
      svn_pool_destroy(connection_pool);

      return err;
    }

#ifdef WIN32
  /* If svnserve needs to run as a Win32 service, then we need to
     coordinate with the Service Control Manager (SCM) before
     continuing.  This function call registers the svnserve.exe
     process with the SCM, waits for the "start" command from the SCM
     (which will come very quickly), and confirms that those steps
     succeeded.

     After this call succeeds, the service is free to run.  At some
     point in the future, the SCM will send a message to the service,
     requesting that it stop.  This is translated into a call to
     winservice_notify_stop().  The service is then responsible for
     cleanly terminating.

     We need to do this before actually starting the service logic
     (opening files, sockets, etc.) because the SCM wants you to
     connect *first*, then do your service-specific logic.  If the
     service process takes too long to connect to the SCM, then the
     SCM will decide that the service is busted, and will give up on
     it.
     */
  if (run_mode == run_mode_service)
    {
      err = winservice_start();
      if (err)
        {
          svn_handle_error2(err, stderr, FALSE, "svnserve: ");

          /* This is the most common error.  It means the user started
             svnserve from a shell, and specified the --service
             argument.  svnserve cannot be started, as a service, in
             this way.  The --service argument is valid only valid if
             svnserve is started by the SCM. */
          if (err->apr_err ==
              APR_FROM_OS_ERROR(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT))
            {
              svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                  _("svnserve: The --service flag is only valid if the"
                    " process is started by the Service Control Manager.\n")));
            }

          svn_error_clear(err);
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }

      /* The service is now in the "starting" state.  Before the SCM will
         consider the service "started", this thread must call the
         winservice_running() function. */
    }
#endif /* WIN32 */

  /* Make sure we have IPV6 support first before giving apr_sockaddr_info_get
     APR_UNSPEC, because it may give us back an IPV6 address even if we can't
     create IPV6 sockets. */

#if APR_HAVE_IPV6
#ifdef MAX_SECS_TO_LINGER
  /* ### old APR interface */
  status = apr_socket_create(&sock, APR_INET6, SOCK_STREAM, pool);
#else
  status = apr_socket_create(&sock, APR_INET6, SOCK_STREAM, APR_PROTO_TCP,
                             pool);
#endif
  if (status == 0)
    {
      apr_socket_close(sock);
      family = APR_UNSPEC;

      if (prefer_v6)
        {
          if (host == NULL)
            host = "::";
          sockaddr_info_flags = APR_IPV6_ADDR_OK;
        }
      else
        {
          if (host == NULL)
            host = "0.0.0.0";
          sockaddr_info_flags = APR_IPV4_ADDR_OK;
        }
    }
#endif

  status = apr_sockaddr_info_get(&sa, host, family, port,
                                 sockaddr_info_flags, pool);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't get address info"));
    }


#ifdef MAX_SECS_TO_LINGER
  /* ### old APR interface */
  status = apr_socket_create(&sock, sa->family, SOCK_STREAM, pool);
#else
  status = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP,
                             pool);
#endif
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't create server socket"));
    }

  /* Prevents "socket in use" errors when server is killed and quickly
   * restarted. */
  status = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't set options on server socket"));
    }

  status = apr_socket_bind(sock, sa);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't bind server socket"));
    }

  status = apr_socket_listen(sock, ACCEPT_BACKLOG);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't listen on server socket"));
    }

#if APR_HAS_FORK
  if (run_mode != run_mode_listen_once && !foreground)
    /* ### ignoring errors... */
    apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);

  apr_signal(SIGCHLD, sigchld_handler);
#endif

#ifdef SIGPIPE
  /* Disable SIGPIPE generation for the platforms that have it. */
  apr_signal(SIGPIPE, SIG_IGN);
#endif

#ifdef SIGXFSZ
  /* Disable SIGXFSZ generation for the platforms that have it, otherwise
   * working with large files when compiled against an APR that doesn't have
   * large file support will crash the program, which is uncool. */
  apr_signal(SIGXFSZ, SIG_IGN);
#endif

  if (pid_filename)
    SVN_ERR(write_pid_file(pid_filename, pool));

#ifdef WIN32
  status = apr_os_sock_get(&winservice_svnserve_accept_socket, sock);
  if (status)
    winservice_svnserve_accept_socket = INVALID_SOCKET;

  /* At this point, the service is "running".  Notify the SCM. */
  if (run_mode == run_mode_service)
    winservice_running();
#endif

  /* Configure FS caches for maximum efficiency with svnserve.
   * For pre-forked (i.e. multi-processed) mode of operation,
   * keep the per-process caches smaller than the default.
   * Also, apply the respective command line parameters, if given. */
  {
    svn_cache_config_t settings = *svn_cache_config_get();

    if (params.memory_cache_size != -1)
      settings.cache_size = params.memory_cache_size;

    settings.single_threaded = TRUE;
    if (handling_mode == connection_mode_thread)
      {
#if APR_HAS_THREADS
        settings.single_threaded = FALSE;
#else
        /* No requests will be processed at all
         * (see "switch (handling_mode)" code further down).
         * But if they were, some other synchronization code
         * would need to take care of securing integrity of
         * APR-based structures. That would include our caches.
         */
#endif
      }

    svn_cache_config_set(&settings);
  }

#if APR_HAS_THREADS
  SVN_ERR(svn_root_pools__create(&connection_pools));

  if (handling_mode == connection_mode_thread)
    {
      /* create the thread pool with a valid range of threads */
      if (max_thread_count < 1)
        max_thread_count = 1;
      if (min_thread_count > max_thread_count)
        min_thread_count = max_thread_count;

      status = apr_thread_pool_create(&threads,
                                      min_thread_count,
                                      max_thread_count,
                                      pool);
      if (status)
        {
          return svn_error_wrap_apr(status, _("Can't create thread pool"));
        }

      /* let idle threads linger for a while in case more requests are
         coming in */
      apr_thread_pool_idle_wait_set(threads, THREADPOOL_THREAD_IDLE_LIMIT);

      /* don't queue requests unless we reached the worker thread limit */
      apr_thread_pool_threshold_set(threads, 0);
    }
  else
    {
      threads = NULL;
    }
#endif

  while (1)
    {
      connection_t *connection = NULL;
      SVN_ERR(accept_connection(&connection, sock, &params, handling_mode,
                                pool));
      if (run_mode == run_mode_listen_once)
        {
          err = serve_socket(connection, connection->pool);
          close_connection(connection);
          return err;
        }

      switch (handling_mode)
        {
        case connection_mode_fork:
#if APR_HAS_FORK
          status = apr_proc_fork(&proc, connection->pool);
          if (status == APR_INCHILD)
            {
              /* the child would't listen to the main server's socket */
              apr_socket_close(sock);

              /* serve_socket() logs any error it returns, so ignore it. */
              svn_error_clear(serve_socket(connection, connection->pool));
              close_connection(connection);
              return SVN_NO_ERROR;
            }
          else if (status != APR_INPARENT)
            {
              err = svn_error_wrap_apr(status, "apr_proc_fork");
              logger__log_error(params.logger, err, NULL, NULL);
              svn_error_clear(err);
            }
#endif
          break;

        case connection_mode_thread:
          /* Create a detached thread for each connection.  That's not a
             particularly sophisticated strategy for a threaded server, it's
             little different from forking one process per connection. */
#if APR_HAS_THREADS
          attach_connection(connection);

          status = apr_thread_pool_push(threads, serve_thread, connection,
                                        0, NULL);
          if (status)
            {
              return svn_error_wrap_apr(status, _("Can't push task"));
            }
#endif
          break;

        case connection_mode_single:
          /* Serve one connection at a time. */
          /* serve_socket() logs any error it returns, so ignore it. */
          svn_error_clear(serve_socket(connection, connection->pool));
        }

      close_connection(connection);
    }

  /* NOTREACHED */
}