Beispiel #1
0
int main(int argc,
         char **argv)
{
  int socketlisten;
  struct sockaddr_in addresslisten;
  struct event accept_event;
  int reuse = 1;

  event_init();

  socketlisten = socket(AF_INET, SOCK_STREAM, 0);

  if (socketlisten < 0)
    {
      fprintf(stderr,"Failed to create listen socket");
      return 1;
    }

  memset(&addresslisten, 0, sizeof(addresslisten));

  addresslisten.sin_family = AF_INET;
  addresslisten.sin_addr.s_addr = INADDR_ANY;
  addresslisten.sin_port = htons(SERVER_PORT);

  if (bind(socketlisten,
           (struct sockaddr *)&addresslisten,
           sizeof(addresslisten)) < 0)
    {
      fprintf(stderr,"Failed to bind");
      return 1;
    }

  if (listen(socketlisten, 5) < 0)
    {
      fprintf(stderr,"Failed to listen to socket");
      return 1;
    }

  setsockopt(socketlisten,
             SOL_SOCKET,
             SO_REUSEADDR,
             &reuse,
             sizeof(reuse));

  setnonblock(socketlisten);

  event_set(&accept_event,
            socketlisten,
            EV_READ|EV_PERSIST,
            accept_callback,
            NULL);

  event_add(&accept_event,
            NULL);

  event_dispatch();

  close(socketlisten);

  return 0;
}
Beispiel #2
0
/* hand off the command. return child connection to the main program */
afp_child_t *dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval)
{
  pid_t pid;
  unsigned int ipc_fds[2];  
  afp_child_t *child;

  if (socketpair(PF_UNIX, SOCK_STREAM, 0, ipc_fds) < 0) {
      LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
      exit( EXITERR_CLNT );
  }

  if (setnonblock(ipc_fds[0], 1) != 0 || setnonblock(ipc_fds[1], 1) != 0) {
      LOG(log_error, logtype_dsi, "dsi_getsess: setnonblock: %s", strerror(errno));
      exit(EXITERR_CLNT);
  }

  switch (pid = dsi->proto_open(dsi)) { /* in libatalk/dsi/dsi_tcp.c */
  case -1:
    /* if we fail, just return. it might work later */
    LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
    return NULL;

  case 0: /* child. mostly handled below. */
    break;

  default: /* parent */
    /* using SIGQUIT is hokey, but the child might not have
     * re-established its signal handler for SIGTERM yet. */
    if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds)) < 0) {
      LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
      dsi->header.dsi_flags = DSIFL_REPLY;
      dsi->header.dsi_code = DSIERR_SERVBUSY;
      dsi_send(dsi);
      dsi->header.dsi_code = DSIERR_OK;
      kill(pid, SIGQUIT);
    }
    dsi->proto_close(dsi);
    return child;
  }
  
  /* child: check number of open connections. this is one off the
   * actual count. */
  if ((serv_children->count >= serv_children->nsessions) &&
      (dsi->header.dsi_command == DSIFUNC_OPEN)) {
    LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
    dsi->header.dsi_flags = DSIFL_REPLY;
    dsi->header.dsi_code = DSIERR_TOOMANY;
    dsi_send(dsi);
    exit(EXITERR_CLNT);
  }

  /* get rid of some stuff */
  close(dsi->serversock);
  server_child_free(serv_children); 

  switch (dsi->header.dsi_command) {
  case DSIFUNC_STAT: /* send off status and return */
    {
      /* OpenTransport 1.1.2 bug workaround: 
       *
       * OT code doesn't currently handle close sockets well. urk.
       * the workaround: wait for the client to close its
       * side. timeouts prevent indefinite resource use. 
       */
      
      static struct timeval timeout = {120, 0};
      fd_set readfds;
      
      dsi_getstatus(dsi);

      FD_ZERO(&readfds);
      FD_SET(dsi->socket, &readfds);
      free(dsi);
      select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);    
      exit(0);
    }
    break;
    
  case DSIFUNC_OPEN: /* setup session */
    /* set up the tickle timer */
    dsi->timer.it_interval.tv_sec = dsi->timer.it_value.tv_sec = tickleval;
    dsi->timer.it_interval.tv_usec = dsi->timer.it_value.tv_usec = 0;
    signal(SIGPIPE, SIG_IGN); /* we catch these ourselves */
    dsi_opensession(dsi);
    if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
        exit(EXITERR_SYS);
    child->ipc_fds[1] = ipc_fds[1];
    return child;
    break;

  default: /* just close */
    LOG(log_info, logtype_dsi, "DSIUnknown %d", dsi->header.dsi_command);
    dsi->proto_close(dsi);
    exit(EXITERR_CLNT);
  }
}
/**
* This function will be called by libevent when there is a connection
* ready to be accepted.
*/
void on_accept(int fd, short ev, void *arg) {
	int client_fd;
	struct sockaddr_in client_addr;
	socklen_t client_len = sizeof(client_addr);
	workqueue_t *workqueue = (workqueue_t *)arg;
	client_t *client;
	job_t *job;

	client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
	if (client_fd < 0) {
		warn("accept failed");
		return;
	}
	printf("Run accept fd:%d\n", fd);
	/* Set the client socket to non-blocking mode. */
	if (setnonblock(client_fd) < 0) {
		;
		warn("failed to set client socket to non-blocking");
		close(client_fd);
		return;
	}

	/* Create a client object. */
	if ((client = (client_t *)malloc(sizeof(*client))) == NULL) {
		warn("failed to allocate memory for client state");
		close(client_fd);
		return;
	}
	memset(client, 0, sizeof(*client));
	client->fd = client_fd;

	/* Add any custom code anywhere from here to the end of this function
	* to initialize your application-specific attributes in the client struct. */

	if ((client->output_buffer = evbuffer_new()) == NULL) {
		warn("client output buffer allocation failed");
		closeAndFreeClient(client);
		return;
	}

	if ((client->evbase = event_base_new()) == NULL) {
		warn("client event_base creation failed");
		closeAndFreeClient(client);
		return;
	}

	/* Create the buffered event.
	*
	* The first argument is the file descriptor that will trigger
	* the events, in this case the clients socket.
	*
	* The second argument is the callback that will be called
	* when data has been read from the socket and is available to
	* the application.
	*
	* The third argument is a callback to a function that will be
	* called when the write buffer has reached a low watermark.
	* That usually means that when the write buffer is 0 length,
	* this callback will be called.  It must be defined, but you
	* don't actually have to do anything in this callback.
	*
	* The fourth argument is a callback that will be called when
	* there is a socket error.  This is where you will detect
	* that the client disconnected or other socket errors.
	*
	* The fifth and final argument is to store an argument in
	* that will be passed to the callbacks.  We store the client
	* object here.
	*/
	if ((client->buf_ev = bufferevent_new(client_fd, buffered_on_read, buffered_on_write, buffered_on_error, client)) == NULL) {
		warn("client bufferevent creation failed");
		closeAndFreeClient(client);
		return;
	}
	bufferevent_base_set(client->evbase, client->buf_ev);

	bufferevent_settimeout(client->buf_ev, SOCKET_READ_TIMEOUT_SECONDS, SOCKET_WRITE_TIMEOUT_SECONDS);

	/* We have to enable it before our callbacks will be
	* called. */
	bufferevent_enable(client->buf_ev, EV_READ);

	/* Create a job object and add it to the work queue. */
	if ((job = (job_t *)malloc(sizeof(*job))) == NULL) {
		warn("failed to allocate memory for job state");
		closeAndFreeClient(client);
		return;
	}
	job->job_function = server_job_function;
	job->user_data = client;

	workqueue_add_job(workqueue, job);
}
/**
* Run the server.  This function blocks, only returning when the server has terminated.
*/
int runServer(void) {
	int sockfd;
	struct sockaddr_in listen_addr;
	struct event ev_accept;
	int reuseaddr_on;

	/* Initialize libevent. */
	event_init();

	/* Set signal handlers
	 sigset_t:信号集,其被定义为一种数据类型
	 struct sigaction {
	 void     (*sa_handler)(int);	//此参数和signal()的参数handler 相同, 代表新的信号处理函数
	 void     (*sa_sigaction)(int, siginfo_t *, void *);
	 sigset_t   sa_mask;			//用来设置在处理该信号时暂时将sa_mask 指定的信号搁置
	 int        sa_flags;			//用来设置信号处理的其他相关操作,  A_NOCLDSTOP: 如果参数signum 为SIGCHLD, 则当子进程暂停时并不会通知父进程;SA_RESTART: 被信号中断的系统调用会自行重启;
	 void     (*sa_restorer)(void);	//此参数没有使用
	 };
	*/
	sigset_t sigset;
	sigemptyset(&sigset);	//初始化信号集,信号集里面的所有信号被清空
	/*struct sigaction siginfo = {
		.sa_handler = sighandler,
		.sa_mask = sigset,
		.sa_flags = SA_RESTART,
		};*/
	struct sigaction siginfo;
	siginfo.sa_handler = sighandler;
	siginfo.sa_mask = sigset;
	siginfo.sa_flags = SA_RESTART;
	sigaction(SIGINT, &siginfo, NULL);	//程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出 
	sigaction(SIGTERM, &siginfo, NULL);	//程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理.通常用来要求程序自己正常退出.shell命令kill缺省产生这个信号.
	/* Create our listening socket. */
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0) {
		err(1, "listen failed");
	}
	memset(&listen_addr, 0, sizeof(listen_addr));
	listen_addr.sin_family = AF_INET;
	listen_addr.sin_addr.s_addr = INADDR_ANY;
	listen_addr.sin_port = htons(SERVER_PORT);
	if (bind(sockfd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
		err(1, "bind failed");
	}
	if (listen(sockfd, CONNECTION_BACKLOG) < 0) {
		err(1, "listen failed");
	}
	reuseaddr_on = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on));

	/* Set the socket to non-blocking, this is essential in event
	* based programming with libevent. */
	if (setnonblock(sockfd) < 0) {
		err(1, "failed to set server socket to non-blocking");
	}
	evbase_accept = event_base_new();
	if (NULL == evbase_accept)
	{
		perror("Unable to create socket accept event base");
		close(sockfd);
		return 1;
	}

	/* Initialize work queue. */
	if (workqueue_init(&workqueue, NUM_THREADS)) {
		perror("Failed to create work queue");
		close(sockfd);
		workqueue_shutdown(&workqueue);
		return 1;
	}

	/* We now have a listening socket, we create a read event to
	* be notified when a client connects. */
	event_set(&ev_accept, sockfd, EV_READ | EV_PERSIST, on_accept, (void *)&workqueue);
	event_base_set(evbase_accept, &ev_accept);
	event_add(&ev_accept, NULL);

	printf("Server is running...\n");

	/* Start the event loop. */
	event_base_dispatch(evbase_accept);

	event_base_free(evbase_accept);
	evbase_accept = NULL;

	close(sockfd);

	printf("Server shutdown.\n");

	return 0;
}
Beispiel #5
0
/**
 * Run the server.  This function blocks, only returning when the server has terminated.
 */
int runServer(void) {
	int listenfd;
	struct sockaddr_in listen_addr;
	struct event ev_accept;
	int reuseaddr_on;

	/* Initialize libevent. */
	event_init();

	/* Set signal handlers */
	sigset_t sigset;
	sigemptyset(&sigset);
	struct sigaction siginfo = {
		.sa_handler = sighandler,
		.sa_mask = sigset,
		.sa_flags = SA_RESTART,
	};
	sigaction(SIGINT, &siginfo, NULL);
	sigaction(SIGTERM, &siginfo, NULL);

	/* Create our listening socket. */
	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd < 0) {
		err(1, "listen failed");
	}
	memset(&listen_addr, 0, sizeof(listen_addr));
	listen_addr.sin_family = AF_INET;
	listen_addr.sin_addr.s_addr = INADDR_ANY;
	listen_addr.sin_port = htons(SERVER_PORT);
	if (bind(listenfd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
		err(1, "bind failed");
	}
	if (listen(listenfd, CONNECTION_BACKLOG) < 0) {
		err(1, "listen failed");
	}
	reuseaddr_on = 1;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on));

	/* Set the socket to non-blocking, this is essential in event
	 * based programming with libevent. */
	if (setnonblock(listenfd) < 0) {
		err(1, "failed to set server socket to non-blocking");
	}

	if ((evbase_accept = event_base_new()) == NULL) {
		perror("Unable to create socket accept event base");
		close(listenfd);
		return 1;
	}

	/* Initialize work queue. */
	if (workqueue_init(&workqueue, NUM_THREADS)) {
		perror("Failed to create work queue");
		close(listenfd);
		workqueue_shutdown(&workqueue);
		return 1;
	}

	/* We now have a listening socket, we create a read event to
	 * be notified when a client connects. */
	event_set(&ev_accept, listenfd, EV_READ|EV_PERSIST, on_accept, (void *)&workqueue);
	event_base_set(evbase_accept, &ev_accept);
	event_add(&ev_accept, NULL);

	printf("Server running.\n");

	/* Start the event loop. */
	event_base_dispatch(evbase_accept);

	event_base_free(evbase_accept);
	evbase_accept = NULL;

	close(listenfd);

	printf("Server shutdown.\n");

	return 0;
}
Beispiel #6
0
/**
 * @brief connect to a host
 *
 * @see
 * @note
 *     h: pointer to s_host_t
 *     recv_sec: receive timeout seconds, 0 for never timeout
 *     return the socket when succ
 *     return < 0 when error, specially HOST_DOWN_FAIL indicate host dead
 * @author auxten <*****@*****.**> <*****@*****.**>
 * @date 2011-8-1
 **/
int connect_host(s_host_t * h, int recv_sec, int send_sec)
{
    int sock = -1;
    int ret;
    int select_ret;
    int res;
    socklen_t res_size = sizeof res;
    struct sockaddr_in channel;
    in_addr_t host;
    int addr_len;
    struct timeval recv_timeout;
    struct timeval send_timeout;
#if HAVE_POLL
#else
    fd_set wset;
#endif /* HAVE_POLL */

    addr_len = getaddr_my(h->addr, &host);
    if (FAIL_CHECK(!addr_len))
    {
        gko_log(WARNING, "gethostbyname %s error", h->addr);
        ret = -1;
        goto CONNECT_END;
    }
    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (FAIL_CHECK(sock < 0))
    {
        gko_log(WARNING, "get socket error");
        ret = -1;
        goto CONNECT_END;
    }

    recv_timeout.tv_usec = 0;
    recv_timeout.tv_sec = recv_sec ? recv_sec : RCV_TIMEOUT;
    send_timeout.tv_usec = 0;
    send_timeout.tv_sec = send_sec ? send_sec : SND_TIMEOUT;

    memset(&channel, 0, sizeof(channel));
    channel.sin_family = AF_INET;
    memcpy(&channel.sin_addr.s_addr, &host, addr_len);
    channel.sin_port = htons(h->port);

    /** set the connect non-blocking then blocking for add timeout on connect **/
    if (FAIL_CHECK(setnonblock(sock) < 0))
    {
        gko_log(WARNING, "set socket non-blocking error");
        ret = -1;
        goto CONNECT_END;
    }

    /** connect and send the msg **/
    if (FAIL_CHECK(connect(sock, (struct sockaddr *) &channel, sizeof(channel)) &&
            errno != EINPROGRESS))
    {
        gko_log(WARNING, "connect error");
        ret = HOST_DOWN_FAIL;
        goto CONNECT_END;
    }

    /** Wait for write bit to be set **/
#if HAVE_POLL
    {
        struct pollfd pollfd;

        pollfd.fd = sock;
        pollfd.events = POLLOUT;

        /* send_sec is in seconds, timeout in ms */
        select_ret = poll(&pollfd, 1, (int)(send_sec * 1000 + 1));
    }
#else
    {
        FD_ZERO(&wset);
        FD_SET(sock, &wset);
        select_ret = select(sock + 1, 0, &wset, 0, &send_timeout);
    }
#endif /* HAVE_POLL */
    if (select_ret < 0)
    {
        gko_log(WARNING, "select/poll error on connect");
        ret = HOST_DOWN_FAIL;
        goto CONNECT_END;
    }
    if (!select_ret)
    {
        gko_log(WARNING, "connect timeout on connect");
        ret = HOST_DOWN_FAIL;
        goto CONNECT_END;
    }

    /**
     * check if connection is RESETed, maybe this is the
     * best way to do that
     * SEE: http://cr.yp.to/docs/connect.html
     **/
    (void) getsockopt(sock, SOL_SOCKET, SO_ERROR, &res, &res_size);
    if (CONNECT_DEST_DOWN(res))
    {
//        gko_log(NOTICE, "connect dest is down errno: %d", res);
        ret = HOST_DOWN_FAIL;
        goto CONNECT_END;
    }

    ///gko_log(WARNING, "selected %d ret %d, time %d", sock, select_ret, send_timeout.tv_sec);
    /** set back blocking **/
    if (FAIL_CHECK(setblock(sock) < 0))
    {
        gko_log(WARNING, "set socket non-blocking error");
        ret = -1;
        goto CONNECT_END;
    }

    /** set recv & send timeout **/
    if (FAIL_CHECK(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &recv_timeout,
                    sizeof(struct timeval))))
    {
        gko_log(WARNING, "setsockopt SO_RCVTIMEO error");
        ret = -1;
        goto CONNECT_END;
    }
    if (FAIL_CHECK(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &send_timeout,
                    sizeof(struct timeval))))
    {
        gko_log(WARNING, "setsockopt SO_SNDTIMEO error");
        ret = -1;
        goto CONNECT_END;
    }

    ret = sock;

    CONNECT_END:
    ///
    if (ret < 0 && sock >= 0)
    {
        close_socket(sock);
    }
    return ret;
}
Beispiel #7
0
bool Mineserver::run()
{
    uint32_t starttime = (uint32_t)time(0);
    uint32_t tick      = (uint32_t)time(0);


    // load plugins
    if (config()->has("system.plugins") && (config()->type("system.plugins") == CONFIG_NODE_LIST))
    {
        std::list<std::string> tmp = config()->mData("system.plugins")->keys();
        for (std::list<std::string>::const_iterator it = tmp.begin(); it != tmp.end(); ++it)
        {
            std::string path  = config()->sData("system.path.plugins");
            std::string name  = config()->sData("system.plugins." + (*it));
            std::string alias = *it;
            if (name[0] == '_')
            {
                path = "";
                alias = name;
                name = name.substr(1);
            }

            plugin()->loadPlugin(name, path, alias);
        }
    }

    // Initialize map
    for (int i = 0; i < (int)m_map.size(); i++)
    {
        physics(i)->enabled = (config()->bData("system.physics.enabled"));
        redstone(i)->enabled = (config()->bData("system.redstone.enabled"));

        m_map[i]->init(i);
        if (config()->bData("map.generate_spawn.enabled"))
        {
            LOG2(INFO, "Generating spawn area...");
            int size = config()->iData("map.generate_spawn.size");
            bool show_progress = config()->bData("map.generate_spawn.show_progress");
#ifdef __FreeBSD__
            show_progress = false;
#endif

#ifdef WIN32
            DWORD t_begin = 0, t_end = 0;
#else
            clock_t t_begin = 0, t_end = 0;
#endif

            for (int x = -size; x <= size; x++)
            {
                if (show_progress)
                {
#ifdef WIN32
                    t_begin = timeGetTime();
#else
                    t_begin = clock();
#endif
                }
                for (int z = -size; z <= size; z++)
                {
                    m_map[i]->loadMap(x, z);
                }

                if (show_progress)
                {
#ifdef WIN32
                    t_end = timeGetTime();
                    LOG2(INFO, dtos((x + size + 1) *(size * 2 + 1)) + "/" + dtos((size * 2 + 1) *(size * 2 + 1)) + " done. " + dtos((t_end - t_begin) / (size * 2 + 1)) + "ms per chunk");
#else
                    t_end = clock();
                    LOG2(INFO, dtos((x + size + 1) *(size * 2 + 1)) + "/" + dtos((size * 2 + 1) *(size * 2 + 1)) + " done. " + dtos(((t_end - t_begin) / (CLOCKS_PER_SEC / 1000)) / (size * 2 + 1)) + "ms per chunk");
#endif
                }
            }
        }
        // Choose proper spawn position
        m_map[i]->chooseSpawnPosition();
#ifdef DEBUG
        LOG(DEBUG, "Map", "Spawn area ready!");
#endif
    }

    // Initialize packethandler
    packetHandler()->init();

    // Load ip from config
    const std::string ip = config()->sData("net.ip");

    // Load port from config
    const int port = config()->iData("net.port");

#ifdef WIN32
    WSADATA wsaData;
    int iResult;
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0)
    {
        LOG2(ERROR, std::string("WSAStartup failed with error: " + iResult));
        return false;
    }
#endif

    struct sockaddr_in addresslisten;
    int reuse = 1;

    m_eventBase = reinterpret_cast<event_base*>(event_init());
#ifdef WIN32
    m_socketlisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#else
    m_socketlisten = socket(AF_INET, SOCK_STREAM, 0);
#endif

    if (m_socketlisten < 0)
    {
        LOG2(ERROR, "Failed to create listen socket");
        return false;
    }

    memset(&addresslisten, 0, sizeof(addresslisten));

    addresslisten.sin_family      = AF_INET;
    addresslisten.sin_addr.s_addr = inet_addr(ip.c_str());
    addresslisten.sin_port        = htons(port);

    //Reuse the socket
    setsockopt(m_socketlisten, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));

    // Bind to port
    if (bind(m_socketlisten, (struct sockaddr*)&addresslisten, sizeof(addresslisten)) < 0)
    {
        LOG2(ERROR, "Failed to bind to " + ip + ":" + dtos(port));
        return false;
    }

    if (listen(m_socketlisten, 5) < 0)
    {
        LOG2(ERROR, "Failed to listen to socket");
        return false;
    }

    setnonblock(m_socketlisten);
    event_set(&m_listenEvent, m_socketlisten, EV_WRITE | EV_READ | EV_PERSIST, accept_callback, NULL);
    event_add(&m_listenEvent, NULL);

    LOG2(INFO, "Listening on: ");
    if (ip == "0.0.0.0")
    {
        // Print all local IPs
        char name[255];
        gethostname(name, sizeof(name));
        struct hostent* hostinfo = gethostbyname(name);
        int ipIndex = 0;
        while (hostinfo && hostinfo->h_addr_list[ipIndex])
        {
            const std::string ip(inet_ntoa(*(struct in_addr*)hostinfo->h_addr_list[ipIndex++]));
            LOG2(INFO, ip + ":" + dtos(port));
        }
    }
    else
    {
        LOG2(INFO, ip + ":" + dtos(port));
    }

    //Let event_base_loop lock for 200ms
    timeval loopTime;
    loopTime.tv_sec  = 0;
    loopTime.tv_usec = 200000; // 200ms

    m_running = true;
    event_base_loopexit(m_eventBase, &loopTime);

    // Create our Server Console user so we can issue commands

    time_t timeNow = time(NULL);
    while (m_running && event_base_loop(m_eventBase, 0) == 0)
    {
        event_base_loopexit(m_eventBase, &loopTime);

        // Run 200ms timer hook
        runAllCallback("Timer200");

        //Remove any users pending removal
        if(m_usersToRemove.size())
        {
            for (std::set<User*>::iterator it = m_usersToRemove.begin(); it != m_usersToRemove.end(); it++)
            {
                User* u = *it;
                delete u;
                u = 0;
            }
            m_usersToRemove.clear();
        }



        // Alert any block types that care about timers
        for (size_t i = 0 ; i < plugin()->getBlockCB().size(); ++i)
        {
            const BlockBasicPtr blockcb = plugin()->getBlockCB()[i];
            if (blockcb != NULL)
            {
                blockcb->timer200();
            }
        }

        //Update physics every 200ms
        for (std::vector<Map*>::size_type i = 0 ; i < m_map.size(); i++)
        {
            physics(i)->update();
            redstone(i)->update();
        }


        //Every 10 seconds..
        timeNow = time(0);
        if (timeNow - starttime > 10)
        {
            starttime = (uint32_t)timeNow;

            //Map saving on configurable interval
            if (m_saveInterval != 0 && timeNow - m_lastSave >= m_saveInterval)
            {
                //Save
                for (std::vector<Map*>::size_type i = 0; i < m_map.size(); i++)
                {
                    m_map[i]->saveWholeMap();
                }

                m_lastSave = timeNow;
            }

            // If users, ping them
            if (!User::all().empty())
            {
                // Send server time and keepalive
                Packet pkt;
                pkt << Protocol::timeUpdate(m_map[0]->mapTime);
                pkt << Protocol::keepalive(0);
                pkt << Protocol::playerlist();
                (*User::all().begin())->sendAll(pkt);
            }

            //Check for tree generation from saplings
            for (size_t i = 0; i < m_map.size(); ++i)
            {
                m_map[i]->checkGenTrees();
            }

            // TODO: Run garbage collection for chunk storage dealie?

            // Run 10s timer hook
            runAllCallback("Timer10000");
        }

        // Every second
        if (timeNow - tick > 0)
        {
            tick = (uint32_t)timeNow;
            std::set<User*> usersToRemove;
            // Loop users
            for (std::set<User*>::iterator it = m_users.begin(); it != m_users.end(); it++)
            {
                User * const & u = *it;

                // No data received in 30s, timeout
                if (u->logged && timeNow - u->lastData > 30)
                {
                    LOG2(INFO, "Player " + u->nick + " timed out");
                    usersToRemove.insert(u);

                }
                else if (!u->logged && timeNow - u->lastData > 100)
                {
                    usersToRemove.insert(u);
                }
                else
                {
                    if (m_damage_enabled)
                    {
                        u->checkEnvironmentDamage();
                    }
                    u->pushMap();
                    u->popMap();
                }
            }
            for (std::set<User*>::iterator it = usersToRemove.begin(); it != usersToRemove.end(); it++)
            {
                delete *it;
            }

            for (std::vector<Map*>::size_type i = 0 ; i < m_map.size(); i++)
            {
                m_map[i]->mapTime += 20;
                if (m_map[i]->mapTime >= 24000)
                {
                    m_map[i]->mapTime = 0;
                }
            }

            for (std::set<User*>::const_iterator it = users().begin(); it != users().end(); ++it)
            {
                (*it)->pushMap();
                (*it)->popMap();
            }

            // Check for Furnace activity
            furnaceManager()->update();

            // Check for user validation results
            pthread_mutex_lock(&ServerInstance->m_validation_mutex);
            for(size_t i = 0; i < ServerInstance->validatedUsers.size(); i++)
            {
                //To make sure user hasn't timed out or anything while validating
                User *tempuser = NULL;
                for (std::set<User*>::const_iterator it = users().begin(); it != users().end(); ++it)
                {
                    if((*it)->UID == ServerInstance->validatedUsers[i].UID)
                    {
                        tempuser = (*it);
                        break;
                    }
                }

                if(tempuser != NULL)
                {
                    if(ServerInstance->validatedUsers[i].valid)
                    {
                        LOG(INFO, "Packets", tempuser->nick + " is VALID ");
                        tempuser->crypted = true;
                        tempuser->buffer << (int8_t)PACKET_ENCRYPTION_RESPONSE << (int16_t)0 << (int16_t) 0;
                        tempuser->uncryptedLeft = 5;
                    }
                    else
                    {
                        tempuser->kick("User not Premium");
                    }
                    //Flush
                    client_write(tempuser);
                }
            }
            ServerInstance->validatedUsers.clear();
            pthread_mutex_unlock(&ServerInstance->m_validation_mutex);

            // Run 1s timer hook
            runAllCallback("Timer1000");
        }

        // Underwater check / drowning
        // ToDo: this could be done a bit differently? - Fador
        // -- User::all() == users() - louisdx


        for (std::set<User*>::const_iterator it = users().begin(); it != users().end(); ++it)
        {
            (*it)->isUnderwater();
            if ((*it)->pos.y < 0)
            {
                (*it)->sethealth((*it)->health - 5);
            }
            //Flush data
            client_write((*it));
        }
    }
#ifdef WIN32
    closesocket(m_socketlisten);
#else
    close(m_socketlisten);
#endif

    saveAll();

    event_base_free(m_eventBase);

    return true;
}
Beispiel #8
0
void child_status(void) { /* dead libwrap or 'exec' process detected */
    int pid, status;

#ifdef HAVE_WAIT_FOR_PID
    while((pid=wait_for_pid(-1, &status, WNOHANG))>0) {
#else
    if((pid=wait(&status))>0) {
#endif
#ifdef WIFSIGNALED
        if(WIFSIGNALED(status)) {
            s_log(LOG_INFO, "Child process %d terminated on signal %d",
                pid, WTERMSIG(status));
        } else {
            s_log(LOG_INFO, "Child process %d finished with code %d",
                pid, WEXITSTATUS(status));
        }
#else
        s_log(LOG_INFO, "Child process %d finished with status %d",
            pid, status);
#endif
    }
}

#endif /* !defined USE_WIN32 */

int alloc_fd(int sock) {
#ifndef USE_WIN32
    if(!max_fds || sock>=max_fds) {
        s_log(LOG_ERR,
            "File descriptor out of range (%d>=%d)", sock, max_fds);
        closesocket(sock);
        return -1;
    }
#endif
    setnonblock(sock, 1);
    return 0;
}

/* Try to use non-POSIX O_NDELAY on obsolete BSD systems */
#if !defined O_NONBLOCK && defined O_NDELAY
#define O_NONBLOCK O_NDELAY
#endif

static void setnonblock(int sock, unsigned long l) {
#if defined F_GETFL && defined F_SETFL && defined O_NONBLOCK
    int retval, flags;
    do {
        flags=fcntl(sock, F_GETFL, 0);
    }while(flags<0 && get_last_socket_error()==EINTR);
    flags=l ? flags|O_NONBLOCK : flags&~O_NONBLOCK;
    do {
        retval=fcntl(sock, F_SETFL, flags);
    }while(retval<0 && get_last_socket_error()==EINTR);
    if(retval<0)
#else
    if(ioctlsocket(sock, FIONBIO, &l)<0)
#endif
        sockerror("nonblocking"); /* non-critical */
    else
        s_log(LOG_DEBUG, "FD %d in %sblocking mode", sock,
            l ? "non-" : "");
}
Beispiel #9
0
int main(int argc, char *argv[]) {
	int want_dump=0;
	int lport;
	int sock, n, i;
	size_t length, fromlen;
	struct sockaddr_in addr;
	struct sockaddr_in from;
	char buf[BUFSIZ];

	remoteconnection *rc = NULL; 

	if (argc == 2) {
		if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
			printversion(argv[0]);
			return (0);
		}
		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
				usage (argv[0], 0);
		}
	}

	if (argc < 2)
		usage(argv[0], 1);

	lport = atoi(argv[1]);
	rc=calloc((argc-2), sizeof(remoteconnection));

	if (argc == 2) {
		want_dump = 1;	
		//printf("raw data dump mode!\n");
	}
	for (i=2; i < argc; i++) {
		char *hostname=NULL;
		int port=0;
		if(!splithp(argv[i], &hostname, &port)) {
			open_rc(&(rc[(i-2)]), hostname, port);
			rc[(i-2)].port=port;
			rc[(i-2)].hostname=hostname;
			//printf(" dup to h:%s p:%i\n", hostname, port);
		}
	}

	sock=socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0)
		error("Opening socket");

	setnonblock(sock, 1);

	int val=1;
#ifndef HAVE_WINDOWS
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val,  sizeof(int));
#else
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val,  sizeof(int));
#endif

	length = sizeof(addr);
	bzero(&addr, length);
	addr.sin_family=AF_INET;
	addr.sin_addr.s_addr=INADDR_ANY;
	addr.sin_port=htons(lport);
	if (bind(sock, (struct sockaddr *)&addr, length)<0)
		error("binding to port %i failed.", lport);
	fromlen = sizeof(struct sockaddr_in);

	run=1;
#ifndef HAVE_WINDOWS
	signal (SIGHUP, catchsig);
	signal (SIGINT, catchsig);
#endif

	while (run) {
    fd_set rfds;
    struct timeval tv;
    tv.tv_sec = 1; tv.tv_usec = 0;

    FD_ZERO(&rfds);
    FD_SET(sock, &rfds);
    if((select(sock+1, &rfds, NULL, NULL, &tv))<0) {
      if (errno!=EINTR) {
        break;
			}
			continue;
    }
    if(!FD_ISSET(sock, &rfds)) 
			continue;

		n = recvfrom(sock, buf, BUFSIZ, 0, (struct sockaddr *)&from, &fromlen);
		if (n < 0)
			error("recvfrom");
		if (want_dump) {
			//printf("Received a datagram: ");
			write(1, buf, n);
			//printf("\n"); 
			fsync(1);
		}
		for (i=2; i < argc; i++) {
			send_rc(&(rc[i-2]), buf, n);
		}
	}

	for (i=2; i < argc; i++) {
		close_rc(&(rc[i-2]));
		free(rc[(i-2)].hostname);
	}
#ifndef HAVE_WINDOWS
    close(sock); 
#else
    closesocket(sock);
#endif

	return (0);
}
int main() {
	#if defined _WIN32
	WORD w_version_requested;
	WSADATA wsa_data;
	int err;
	w_version_requested = MAKEWORD(2, 2);

	err = WSAStartup(w_version_requested, &wsa_data);
	if (err != 0) {
		printf("WSAStartup failed with error: %d\n", err);
		return 1;
	}
	#endif

	EV_A = ev_default_loop(0);
	if (EV_A == NULL) {
		printf("ev_default_loop failed!\n");
		goto error;
	}
	
	struct addrinfo hints;
	struct addrinfo *res;
	char bol_reuseaddr = 1;

	// Get address info
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_PASSIVE;
	int int_status = getaddrinfo(NULL, "8080", &hints, &res);
	if (int_status != 0) {
		wprintf(L"getaddrinfo failed: %d (%s)\n", int_status, gai_strerror(int_status));
		goto error;
	}

	// Get socket to bind
	int_sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (int_sock == INVALID_SOCKET) {
		printf("Failed to create socket: %s (%d)\n", strerror(errno), errno);
		goto error;
	}

	if (setsockopt(int_sock, SOL_SOCKET, SO_REUSEADDR, &bol_reuseaddr, sizeof(int)) == -1) {
		printf("setsockopt failed: %s (%d)\n", strerror(errno), errno);
		goto error;
	}

	if (bind(int_sock, res->ai_addr, res->ai_addrlen) == -1) {
		printf("bind failed: %s (%d)\n", strerror(errno), errno);
		goto error;
	}

	freeaddrinfo(res);

	if (listen(int_sock, 10) == -1) {
		printf("listen failed: %s (%d)\n", strerror(errno), errno);
		goto error;
	}
	
	int int_ret;
	if ((int_ret = setnonblock(int_sock)) != 0) {
		printf("setnonblock failed: %d\n", int_ret);
		goto error;
	}

	#if defined _WIN32
	int fd = _open_osfhandle(int_sock, 0);
	ev_io_init(&server_io, server_cb, fd, EV_READ);
	#else
	ev_io_init(&server_io, server_cb, int_sock, EV_READ);
	#endif
	ev_io_start(EV_A, &server_io);

	ev_run(EV_A, 0);

	#if defined _WIN32
	_close(fd);
	#else
	close(int_sock);
	#endif

	#if defined _WIN32
	WSACleanup();
	#endif
	return 0;
error:
	#if defined _WIN32
	WSACleanup();
	#endif
	return 1;
}
Beispiel #11
0
int main(int argc, char **argv)
{
    ev_stat cfg;
    if (argc == 1) {
        printf("no cfg\n");
        return 0;
    }
    if (argc == 2) {
        daemon(0, 0);
    }
    cfg_path = strdup(argv[1]);
    cfg_init(cfg_path);
    ev_stat_init (&cfg, cfg_cb, cfg_path, 2.);
    signal(SIGPIPE, SIG_IGN);
    struct ev_loop *loop = ev_default_loop (0);
    work_loop = ev_loop_new(0);
    int listen_fd;
    struct sockaddr_in listen_addr; 
    int reuseaddr_on = 1;
   
    pthread_mutex_init(&lock, NULL);
    thread_create(work, NULL);
    listen_fd = socket(AF_INET, SOCK_STREAM, 0); 
    if (listen_fd < 0) {
        perror("listen failed");
        return -1;
    }
    if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on,
            sizeof(reuseaddr_on)) == -1)
    {
        perror("setsockopt failed");
        return -1;
    }
    memset(&listen_addr, 0, sizeof(listen_addr));
    listen_addr.sin_family = AF_INET;
    listen_addr.sin_addr.s_addr = INADDR_ANY;
    listen_addr.sin_port = htons(SERVER_PORT);
    if (bind(listen_fd, (struct sockaddr *)&listen_addr,
            sizeof(listen_addr)) < 0)
    {
        perror("bind failed");
        return -1;
    }
    if (listen(listen_fd, 128) < 0)
    {
        perror("listen failed");
        return -1;
    }
    if (setnonblock(listen_fd) < 0)
    {
        perror("failed to set server socket to non-blocking");
        return -1;
    }
	 
    ev_io ev_accept;
    ev_io_init(&ev_accept, accept_cb, listen_fd, EV_READ);
    ev_io_start(loop, &ev_accept);
    if (cfg_path != NULL)
        ev_stat_start (loop, &cfg);
    ev_loop (loop, 0);
    return 0;
}
Beispiel #12
0
int
main(int argc, char *const *argv)
{
  int
    c,      /* control descriptor (stdin) */
    s;      /* socket descriptor (PuTTY) */
  Buffer
    cbuf,   /* control buffer */
    pbuf,   /* pty buffer */
    sbuf;   /* socket buffer */

  DBUG_INIT_ENV("main",argv[0],"DBUG_OPTS");

#ifndef DBUG_OFF
  setvbuf(DBUG_FILE, 0, _IONBF, 0);
#endif

  /* General steps:
    1. connect to cygterm backend
    2. create pty
    3. fork child process (/bin/bash)
    4. select on pty, cygterm backend forwarding pty data and messages
  */

  if (argc < 4) {
    DBUG_PRINT("error", ("Too few arguments"));
    DBUG_RETURN(CthelperInvalidUsage);
  }

  DBUG_PRINT("startup", ("isatty: (%d,%d,%d)",
    isatty(STDIN_FILENO), isatty(STDOUT_FILENO), isatty(STDERR_FILENO)));
  DBUG_PRINT("startup", (
    "cmdline: [%s] %s %s %s ...", argv[0], argv[1], argv[2], argv[3]));
  {
    extern char **environ;
    char **envp;
    for (envp = environ; *envp; envp++)
      DBUG_PRINT("startup", ("%s", *envp));
  }

  /* It is not necessary to close all open descriptors.  There are no
   * files inherited from the PuTTY process except standard input.
   */
#ifndef DEBUG
  close(STDERR_FILENO);
#endif

  /* Duplicate c and open /dev/null as 0 so that 0 can mean "closed". */
  c = dup(STDIN_FILENO); close(STDIN_FILENO);
  open("/dev/null", O_RDWR);

  /* Command line:
   * argv[1] =  port number
   * argv[2] =  terminal name
   * argv[3] =  terminal characteristics string
   * Any remaining arguments are the command to execute.  If there are no
   * other arguments, use the user's default login shell with a - prefix
   * for its argv[0].
   */
/*
cthelper command line parameters:

cthelper PORT TERM ATTRS [COMMAND [ARGS]]

    PORT
        port number for PuTTY pty input data socket
    TERM
        name of terminal (set TERM environment variable)
    ATTRS
    a colon-separated list of terminal attributes
    See init_pty() for details.
    COMMAND
        Runs COMMAND with ARGS as child process.  If COMMAND is not
        supplied, cthelper will run the user's login shell as specified in
        /etc/passwd specifying "-" for its argv[0] as typical.
*/


  /* connect to cygterm */
  {
    int ct_port = strtol(argv[1], 0, 0);
#ifdef DEBUG
    if (ct_port == 0) {
      /* For debugging purposes, make the tty we are started
       * in the "socket". This allows to test cthelper without
       * putty.exe */
      assert(isatty(STDOUT_FILENO));
      raw();
      atexit(restore);
      c = open("/dev/null", O_RDONLY);
      s = dup(STDOUT_FILENO);
    }
    else 
#endif
    if (ct_port <= 0) {
      DBUG_PRINT("startup", ("invalid port"));
      DBUG_RETURN(CthelperInvalidPort);
    }
    DBUG_PRINT("startup", ("connect cygterm"));
    if (0 > (s = connect_cygterm(ct_port))) {
      DBUG_PRINT("startup", ("connect_cygterm: bad"));
      DBUG_RETURN(CthelperConnectFailed);
    }
    DBUG_PRINT("startup", ("OK"));
  }

  /* initialize buffers */
  DBUG_PRINT("startup", ("initialize buffers"));
  BUFFER_ALLOCA(cbuf, CTLBUF);
  BUFFER_ALLOCA(pbuf, PTOBUF);
  BUFFER_ALLOCA(sbuf, PTIBUF);

  /* set up signal handling */
  signal(SIGCHLD, handle_sigchld);

  /* start child process */
  if (0 > (t = setup_child(&child, argv[2], argv[3], argv + 4))) {
    DBUG_PRINT("startup", ("setup_child failed: %s", strerror(-t)));
    DBUG_RETURN(CthelperPtyforkFailure);
  }

  /*  To explain what is happening here:
   *  's' is the socket between PuTTY and cthelper; it is read to get
   *  input for the tty and written to display output from the pty.
   *  't' is the pseudo terminal; it is read to get pty input which is sent to
   *  PuTTY and written to pass input from PuTTY to the pty.
   *  'c' is standard input, which is a one-way anonymous pipe from PuTTY.
   *  It is read to receive special messages from PuTTY such as
   *  terminal resize events.
   *
   *  This is the flow of data through the buffers:
   *      s => sbuf => t
   *      t => pbuf => s
   *      c => cbuf => process_message()
   *
   *  When 't' is closed, we close(s) to signal PuTTY we are done.
   *  When 's' is closed, we kill(child, HUP) to kill the child process.
   */

  setnonblock(c);
  setnonblock(s);
  setnonblock(t);

  DBUG_PRINT("info", ("c==%d, s==%d, t==%d", c, s, t));
  /* allow easy select() and FD_ISSET() stuff */
  assert(0 < c && c < s && s < t);
  DBUG_PRINT("startup", ("starting select loop"));
  while (s || t) {
    int n = 0;
    fd_set r, w;
    DBUG_ENTER("select");
    FD_ZERO(&r); FD_ZERO(&w);
    if (c && !buffer_isfull(cbuf)) { FD_SET(c, &r); n = c; }
    if (s && !buffer_isfull(sbuf)) { FD_SET(s, &r); n = s; }
    if (s && !buffer_isempty(pbuf)) { FD_SET(s, &w); n = s; }
    if (t && !buffer_isfull(pbuf)) { FD_SET(t, &r); n = t; }
    if (t && !buffer_isempty(sbuf)) { FD_SET(t, &w); n = t; }
    switch (n = select(n + 1, &r, &w, 0, 0)) {
    case -1:
      DBUG_PRINT("error", ("%s", strerror(errno)));
      if (errno != EINTR) {
        /* Something bad happened */
        close(c); c = 0;
        close(s); s = 0;
        close(t); t = 0;
      }
      break;
    case 0:
      DBUG_PRINT("info", ("select timeout"));
      break;
    default:
      DBUG_PRINT("info", ("%d ready descriptors [[r==%lx,w==%lx]]", n, *(unsigned long *)&r, *(unsigned long *)&w));
      if (FD_ISSET(c, &r)) {
        DBUG_ENTER("c=>cbuf");
        switch (buffer_read(cbuf, c)) {
        case -1:
          DBUG_PRINT("error", ("error reading c: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* PuTTY closed the message pipe */
          DBUG_PRINT("io", ("c closed"));
          close(c); c = 0;
          break;
        default:
          DBUG_PRINT("io", ("cbuf => process_message()"));
          process_message(cbuf, t);
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(s, &r)) {
        DBUG_ENTER("s=>sbuf");
        switch (buffer_read(sbuf, s)) {
        case -1:
          DBUG_PRINT("error", ("error reading s: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* PuTTY closed the socket */
          DBUG_PRINT("io", ("s closed"));
          close(s); s = 0;
          break;
        default:
          FD_SET(t, &w);
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(t, &r)) {
        DBUG_ENTER("t=>pbuf");
        switch (buffer_read(pbuf, t)) {
        case -1:
          DBUG_PRINT("error", ("error reading t: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* pty closed */
          DBUG_PRINT("io", ("t closed"));
          if (!FD_ISSET(t, &w)) {
            close(t); t = 0;
          }
          break;
        default:
          FD_SET(s, &w);
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(t, &w)) {
        DBUG_ENTER("sbuf=>t");
        switch (buffer_write(sbuf, t)) {
        case -1:
          DBUG_PRINT("error", ("error writing t: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* pty closed */
          DBUG_PRINT("io", ("t closed"));
          close(t); t = 0;
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(s, &w)) {
        DBUG_ENTER("pbuf=>s");
        switch (buffer_write(pbuf, s)) {
        case -1:
          DBUG_PRINT("error", ("error writing s: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* PuTTY closed the socket */
          DBUG_PRINT("io", ("s closed"));
          close(s); s = 0;
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      DBUG_PRINT("info", ("[[n==%d,r==%lx,w==%lx]]", n, *(unsigned long *)&r, *(unsigned long *)&w));
      assert(n == 0);
      break;
    }

    if (child_signalled) check_child();

    if (!t && buffer_isempty(pbuf)) {
      DBUG_PRINT("info", ("shutdown socket"));
      shutdown(s, SHUT_WR);
    }

    if (!s && buffer_isempty(sbuf) && child_alive()) {
      DBUG_PRINT("sig", ("kill child"));
      kill(child, SIGHUP);
      /* handle_sigchld() will close(t) */
    }
    DBUG_LEAVE;
  }
  DBUG_PRINT("info", ("end of select loop"));

  /* ensure child process killed */
  /* XXX I'm not sure if all of this is necessary, but it probably won't
   * hurt anything. */
  if (child_alive() && sleep(1) == 0) {
    DBUG_PRINT("sig", ("waiting for child"));
    waitpid(child, 0, WNOHANG);
  }

  DBUG_PRINT("info", ("goodbye"));
  if (exit_status == 111)
    DBUG_RETURN(CthelperExecFailure);
  DBUG_RETURN(EXIT_SUCCESS);
}
Beispiel #13
0
/**
 * this is what the child process does continuously.  If
 * the child process dies, then it gets respawned by the
 * watchdog to maintain continuity.
 */
static int do_child_process(void) {
    int server_sockfd;
    struct sockaddr_in server_address;
    struct event_base *pbase = NULL;
    struct event evsignal;   /* libdaemon's signal fd */
    struct event evaccept;   /* server socket */
    int retval = 1;

    /* if(lookup_config.drop_core) { */
    /*     const struct rlimit rlim = { */
    /*         RLIM_INFINITY, */
    /*         RLIM_INFINITY */
    /*     }; */

    /*     setrlimit(RLIMIT_CORE, &rlim); */
    /*     prctl(PR_SET_DUMPABLE, 1); */
    /* } */

    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(server_sockfd == -1) {
        ERROR("Cannot create server socket: %s", strerror(errno));
        goto finish;
    }

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = INADDR_ANY;
    server_address.sin_port = htons(config.port);

    if(bind(server_sockfd, (struct sockaddr*)&server_address, (socklen_t)sizeof(server_address)) < 0) {
        ERROR("Bind error: %s", strerror(errno));
        goto finish;
    }

    if(listen(server_sockfd, config.socket_backlog) < 0) {
        ERROR("Listen error: %s", strerror(errno));
        goto finish;
    }

    if(setnonblock(server_sockfd) < 0) {
        ERROR("Could not set server socket to non-blocking: %s", strerror(errno));
        goto finish;
    }

    /* FIXME: drop privs */

    /* set up events */
    pbase = event_init();
    if(!pbase) {
        ERROR("Could not get event_base.  Failing");
        goto finish;
    }

    /* set up event for libdaemon's signal fd */
    event_set(&evsignal, daemon_signal_fd(), EV_READ | EV_PERSIST, on_signal, &evsignal);
    event_add(&evsignal, NULL);

    /* set up events for listening AF_INET socket */
    event_set(&evaccept, server_sockfd, EV_READ | EV_PERSIST, on_accept, &evaccept);
    event_add(&evaccept, NULL);


    while(!g_quitflag) {
        event_base_loop(pbase, EVLOOP_ONCE);
    }

    retval = 0;

 finish:
    if(pbase) {
        event_del(&evaccept);
        event_del(&evsignal);
    }

    if(server_sockfd != -1) {
        shutdown(server_sockfd, SHUT_RDWR);
        close(server_sockfd);
    }

    exit(retval);
}
Beispiel #14
0
/*!
 * non-blocking drop-in replacement for read with timeout using select
 *
 * @param socket          (r)  socket, if in blocking mode, pass "setnonblocking" arg as 1
 * @param data            (rw) buffer for the read data
 * @param lenght          (r)  how many bytes to read
 * @param setnonblocking  (r)  when non-zero this func will enable and disable non blocking
 *                             io mode for the socket
 * @param timeout         (r)  number of seconds to try reading
 *
 * @returns number of bytes actually read or -1 on timeout or error
 */
ssize_t readt(int socket, void *data, const size_t length, int setnonblocking, int timeout)
{
    size_t stored = 0;
    ssize_t len = 0;
    struct timeval now, end, tv;
    fd_set rfds;
    int ret;

    FD_ZERO(&rfds);

    if (setnonblocking) {
        if (setnonblock(socket, 1) != 0)
            return -1;
    }

    /* Calculate end time */
    (void)gettimeofday(&now, NULL);
    end = now;
    end.tv_sec += timeout;

    while (stored < length) {
        len = recv(socket, (char *) data + stored, length - stored, 0);
        if (len == -1) {
            switch (errno) {
            case EINTR:
                continue;
            case EAGAIN:
                FD_SET(socket, &rfds);
                tv.tv_usec = 0;
                tv.tv_sec  = timeout;
                        
                while ((ret = select(socket + 1, &rfds, NULL, NULL, &tv)) < 1) {
                    switch (ret) {
                    case 0:
                        LOG(log_debug, logtype_afpd, "select timeout %d s", timeout);
                        errno = EAGAIN;
                        goto exit;

                    default: /* -1 */
                        switch (errno) {
                        case EINTR:
                            (void)gettimeofday(&now, NULL);
                            if (now.tv_sec > end.tv_sec
                                ||
                                (now.tv_sec == end.tv_sec && now.tv_usec >= end.tv_usec)) {
                                LOG(log_debug, logtype_afpd, "select timeout %d s", timeout);
                                goto exit;
                            }
                            if (now.tv_usec > end.tv_usec) {
                                tv.tv_usec = 1000000 + end.tv_usec - now.tv_usec;
                                tv.tv_sec  = end.tv_sec - now.tv_sec - 1;
                            } else {
                                tv.tv_usec = end.tv_usec - now.tv_usec;
                                tv.tv_sec  = end.tv_sec - now.tv_sec;
                            }
                            FD_SET(socket, &rfds);
                            continue;
                        case EBADF:
                            /* possibly entered disconnected state, don't spam log here */
                            LOG(log_debug, logtype_afpd, "select: %s", strerror(errno));
                            stored = -1;
                            goto exit;
                        default:
                            LOG(log_error, logtype_afpd, "select: %s", strerror(errno));
                            stored = -1;
                            goto exit;
                        }
                    }
                } /* while (select) */
                continue;
            } /* switch (errno) */
            LOG(log_error, logtype_afpd, "read: %s", strerror(errno));
            stored = -1;
            goto exit;
        } /* (len == -1) */
        else if (len > 0)
            stored += len;
        else
            break;
    } /* while (stored < length) */

exit:
    if (setnonblocking) {
        if (setnonblock(socket, 0) != 0)
            return -1;
    }

    if (len == -1 && stored == 0)
        /* last read or select got an error and we haven't got yet anything => return -1*/
        return -1;
    return stored;
}
Beispiel #15
0
pid_t start_prog(int argc, char **argv, Test *test, int *in_fd,
		 char *in_file, char **fifos, char **out_files) {
  int pipefds[2];
  static char **args = NULL;
  static unsigned int nargs = 0;
  char *prog;
  pid_t pid;
  unsigned int i, arg = 0;

  /* Allocate space for the argument list */
  if (nargs < test->nfiles + test->npipes + ARGS_EXTRA + argc - 1) {
    nargs = test->nfiles + test->npipes + ARGS_EXTRA + argc - 1;
    args = realloc(args, nargs * sizeof(char *));
    if (NULL == args) {
      perror("Couldn't allocate space for argument list");
      return -1;
    }
  }

  /* copy argv */
  for (i = 0; i < argc; i++) {
    args[arg++] = argv[i];
  }
  prog = argv[0];

  if (test->in_type == IN_FILE) {
    /* File input, add -i filename to arguments */
    args[arg++] = "-i";
    args[arg++] = in_file;
  } else {
    /* For pipe input, make the pipe and set both ends nonblocking */
    if (0 != pipe(pipefds)) {
      perror("Couldn't make a pipe");
      return -1;
    }
    if (0 != setnonblock("pipe read end", pipefds[0])) return -1;
    if (0 != setnonblock("pipe write end", pipefds[1])) return -1;
  }

  /* Add output files and named pipes to the argument list */
  for (i = 0; i < test->nfiles; i++) args[arg++] = out_files[i];
  for (i = 0; i < test->npipes; i++) args[arg++] = fifos[i];
  args[arg++] = NULL;
  assert(arg <= nargs);

  printf("# Running: %s", prog);
  for (i = 1; i + 1 < arg; i++) printf(" %s", args[i]);
  printf("\n");

  /* Ensure the chld_fds pipe is empty and reset the got_chld flag*/
  if (0 != drain_signal_pipe()) return -1;
  got_chld = 0;

  /* Start the new process */
  pid = fork();
  if (pid < 0) {
    perror("Couldn't fork");
    return -1;
  }

  if (0 == pid) { /* Child */
    int in = fileno(stdin);
    if (test->in_type == IN_FILE) {
      /* Redirect stdin to /dev/null */
      int fd;
      close(in);
      fd = open("/dev/null", O_RDONLY);
      if (-1 == fd) {
	perror("Opening /dev/null");
	exit(EXIT_FAILURE);
      }
      if (fd != in) {
	if (-1 == dup2(fd, in)) {
	  perror("Redirecting stdin");
	  exit(EXIT_FAILURE);
	}
      }
    } else {
      /* Make stdin read from a pipe */
      close(pipefds[1]);
      if (-1 == dup2(pipefds[0], in)) {
	perror("Redirecting stdin");
	exit(EXIT_FAILURE);
      }
    }
    
    execv(prog, args);
    fprintf(stderr, "Couldn't exec %s : %s\n", prog, strerror(errno));
    exit(EXIT_FAILURE);
  } /* End of child code */

  /* Parent */
  if (test->in_type != IN_FILE) {
    close(pipefds[0]);
    *in_fd = pipefds[1];
  }

  printf("# Child PID = %u\n", (unsigned int) pid);

  return pid;
}
Beispiel #16
0
static int tsock_getfd(const char *host, const char *port)
{
    int sock = -1;
    int attr;
    int err;
    struct addrinfo hints, *servinfo, *p;
    int optval;
    socklen_t optlen = sizeof(optval);

    /* Prepare hint for getaddrinfo */
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_NUMERICSERV;

    if ((err = getaddrinfo(host, port, &hints, &servinfo)) != 0) {
        LOG(log_error, logtype_default, "tsock_getfd: getaddrinfo: CNID server %s:%s : %s\n",
            host, port, gai_strerror(err));
        return -1;
    }

    /* loop through all the results and bind to the first we can */
    for (p = servinfo; p != NULL; p = p->ai_next) {
        if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
            LOG(log_info, logtype_default, "tsock_getfd: socket CNID server %s:: %s",
                host, strerror(errno));
            continue;
        }

        attr = 1;
        if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &attr, sizeof(attr)) == -1) {
            LOG(log_error, logtype_cnid, "getfd: set TCP_NODELAY CNID server %s: %s",
                host, strerror(errno));
            close(sock);
            sock = -1;
            return -1;
        }

        if (setnonblock(sock, 1) != 0) {
            LOG(log_error, logtype_cnid, "getfd: setnonblock: %s", strerror(err));
            close(sock);
            sock = -1;
            return -1;
        }

        if (connect(sock, p->ai_addr, p->ai_addrlen) == -1) {
            if (errno == EINPROGRESS) {
                struct timeval tv;
                tv.tv_usec = 0;
                tv.tv_sec  = 5; /* give it five seconds ... */
                fd_set wfds;
                FD_ZERO(&wfds);
                FD_SET(sock, &wfds);

                if ((err = select(sock + 1, NULL, &wfds, NULL, &tv)) == 0) {
                    /* timeout */
                    LOG(log_error, logtype_cnid, "getfd: select timed out for CNID server %s",
                        host);
                    close(sock);
                    sock = -1;
                    continue;
                }
                if (err == -1) {
                    /* select failed */
                    LOG(log_error, logtype_cnid, "getfd: select failed for CNID server %s",
                        host);
                    close(sock);
                    sock = -1;
                    continue;
                }

                if ( ! FD_ISSET(sock, &wfds)) {
                    /* give up */
                    LOG(log_error, logtype_cnid, "getfd: socket not ready connecting to %s",
                        host);
                    close(sock);
                    sock = -1;
                    continue;
                }

                if ((err = getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen)) != 0 || optval != 0) {
                    if (err != 0) {
                        /* somethings very wrong */
                        LOG(log_error, logtype_cnid, "getfd: getsockopt error with CNID server %s: %s",
                            host, strerror(errno));
                    } else {
                        errno = optval;
                        LOG(log_error, logtype_cnid, "getfd: getsockopt says: %s",
                            strerror(errno));
                    }
                    close(sock);
                    sock = -1;
                    continue;
                }
            } else {
                LOG(log_error, logtype_cnid, "getfd: connect CNID server %s: %s",
                    host, strerror(errno));
                close(sock);
                sock = -1;
                continue;
            }
        }

        /* We've got a socket */
        break;
    }

    freeaddrinfo(servinfo);

    if (p == NULL) {
        errno = optval;
        LOG(log_error, logtype_cnid, "tsock_getfd: no suitable network config from CNID server (%s:%s): %s",
            host, port, strerror(errno));
        return -1;
    }

    return(sock);
}
Beispiel #17
0
int main(int argc, char **argv)
{
	int port = SERVER_PORT;
	timeout = 60;
	static int daemon_mode = 0;

	int c;
	while (1) {
		static struct option long_options[] = {
			{"daemon",  no_argument,       &daemon_mode, 1},
			{"file",      required_argument, 0, 'f'},
			{"port",    required_argument, 0, 'p'},
			{"sync",    required_argument, 0, 's'},
			{0, 0, 0, 0}
		};
		int option_index = 0;
		c = getopt_long(argc, argv, "f:p:s:", long_options, &option_index);
		if (c == -1) { break; }
		switch (c) {
			case 0:
				if (long_options[option_index].flag != 0) { break; }
				printf ("option %s", long_options[option_index].name);
				if (optarg) { printf(" with arg %s", optarg); }
				printf("\n");
				break;
			case 'f':
				sync_file = optarg;
				break;
			case 'p':
				port = atoi(optarg);
				break;
			case 's':
				timeout = atoi(optarg);
				break;
			case '?':
				/* getopt_long already printed an error message. */
				break;
			default:
				abort();
		}
	}
	if (daemon_mode == 1) {
		daemonize();
	}
	if (sync_file == NULL) {
		sync_file = "barbershop.snapshot";
	}

	// side snapshot file to hot load a snapshot by sending SIGHUP
	int n = strlen(sync_file);
	load_file = malloc(sizeof(char) * (n + 6));
	sprintf(load_file, "%s.load", sync_file);

	initializePriorityQueue();

	time(&app_stats.started_at);
	app_stats.version = "00.02.01";
	app_stats.updates = 0;
	app_stats.items = 0;
	app_stats.pools = 0;
	
	load_snapshot(sync_file);
	signal(SIGCHLD, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGTSTP, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);
	signal(SIGTTIN, SIG_IGN);
	signal(SIGHUP, signal_handler); /* catch hangup signal */
	signal(SIGTERM, signal_handler); /* catch kill signal */
	
	pthread_t garbage_collector;
	pthread_create(&garbage_collector, NULL, (void *) gc_thread, NULL);

	int listen_fd;
	struct sockaddr_in listen_addr;
	int reuseaddr_on = 1;
	struct event ev_accept;
	event_init();
	listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_fd < 0) { err(1, "listen failed"); }
	if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on)) == -1) { err(1, "setsockopt failed"); }
	memset(&listen_addr, 0, sizeof(listen_addr));
	listen_addr.sin_family = AF_INET;
	listen_addr.sin_addr.s_addr = INADDR_ANY;
	listen_addr.sin_port = htons(port);
	if (bind(listen_fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) { err(1, "bind failed"); }
	if (listen(listen_fd, 5) < 0) { err(1, "listen failed"); }
	if (setnonblock(listen_fd) < 0) { err(1, "failed to set server socket to non-blocking"); }
	event_set(&ev_accept, listen_fd, EV_READ|EV_PERSIST, on_accept, NULL);
	event_add(&ev_accept, NULL);
	event_dispatch();

	return 0;
}