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; }
/* 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; }
/** * 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; }
/** * @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; }
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; }
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-" : ""); }
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; }
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; }
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); }
/** * 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); }
/*! * 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; }
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; }
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); }
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; }