static int send_recv(const string& host, int port, str_ref s0, string& d) { Csocket s; s.open(SOCK_STREAM, true); if (s == -1) { d += "unable to create socket: " + Csocket::error2a(WSAGetLastError()); return 1; } d = (boost::format("server: %s:%d (%s)\r\n") % host % port % Csocket::inet_ntoa(Csocket::get_host(host))).str(); if (s.connect(Csocket::get_host(host), htons(port))) { d += "unable to connect: " + Csocket::error2a(WSAGetLastError()); return 1; } if (s0.size() != s.send(s0)) { d += "unable to send: " + Csocket::error2a(WSAGetLastError()); return 1; } array<char, 4 << 10> d0; while (int e = s.recv(d0)) { if (e == SOCKET_ERROR) { d += "unable to receive: " + Csocket::error2a(WSAGetLastError()); return 1; } d.append(d0.data(), e); } return 0; }
int srv_run(const std::string& table_prefix, bool use_sql, const std::string& conf_file) { for (int i = 0; i < 8; i++) m_secret = m_secret << 8 ^ rand(); m_conf_file = conf_file; m_database.set_name("config", table_prefix + "config"); m_table_prefix = table_prefix; m_use_sql = use_sql; read_config(); if (test_sql()) return 1; if (m_epoll.create() == -1) { std::cerr << "epoll_create failed" << std::endl; return 1; } std::list<Ctcp_listen_socket> lt; std::list<Cudp_listen_socket> lu; for (auto& j : m_config.m_listen_ipas) { for (auto& i : m_config.m_listen_ports) { Csocket l; if (l.open(SOCK_STREAM) == INVALID_SOCKET) std::cerr << "socket failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; else if (l.setsockopt(SOL_SOCKET, SO_REUSEADDR, true), l.bind(j, htons(i))) std::cerr << "bind failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; else if (l.listen()) std::cerr << "listen failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; else { #ifdef SO_ACCEPTFILTER accept_filter_arg afa; bzero(&afa, sizeof(afa)); strcpy(afa.af_name, "httpready"); if (l.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa))) std::cerr << "setsockopt failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; #elif 0 // TCP_DEFER_ACCEPT if (l.setsockopt(IPPROTO_TCP, TCP_DEFER_ACCEPT, 90)) std::cerr << "setsockopt failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; #endif lt.push_back(Ctcp_listen_socket(l)); if (!m_epoll.ctl(EPOLL_CTL_ADD, l, EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLERR | EPOLLHUP, <.back())) continue; } return 1; } for (auto& i : m_config.m_listen_ports) { Csocket l; if (l.open(SOCK_DGRAM) == INVALID_SOCKET) std::cerr << "socket failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; else if (l.setsockopt(SOL_SOCKET, SO_REUSEADDR, true), l.bind(j, htons(i))) std::cerr << "bind failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; else { lu.push_back(Cudp_listen_socket(l)); if (!m_epoll.ctl(EPOLL_CTL_ADD, l, EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP, &lu.back())) continue; } return 1; } } clean_up(); read_db_torrents(); read_db_users(); write_db_torrents(); write_db_users(); #ifndef NDEBUG // test_announce(); #endif #ifndef WIN32 if (m_config.m_daemon) { if (daemon(true, false)) std::cerr << "daemon failed" << std::endl; std::ofstream(m_config.m_pid_file.c_str()) << getpid() << std::endl; struct sigaction act; act.sa_handler = sig_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGTERM, &act, NULL)) std::cerr << "sigaction failed" << std::endl; act.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &act, NULL)) std::cerr << "sigaction failed" << std::endl; } #endif #ifdef EPOLL std::array<epoll_event, 64> events; #else fd_set fd_read_set; fd_set fd_write_set; fd_set fd_except_set; #endif while (!g_sig_term) { #ifdef EPOLL int r = m_epoll.wait(events.data(), events.size(), 5000); if (r == -1) std::cerr << "epoll_wait failed: " << errno << std::endl; else { time_t prev_time = m_time; m_time = ::time(NULL); for (int i = 0; i < r; i++) reinterpret_cast<Cclient*>(events[i].data.ptr)->process_events(events[i].events); if (m_time == prev_time) continue; for (auto i = m_connections.begin(); i != m_connections.end(); ) { if (i->run()) i = m_connections.erase(i); else i++; } } #else FD_ZERO(&fd_read_set); FD_ZERO(&fd_write_set); FD_ZERO(&fd_except_set); int n = 0; for (auto& i : m_connections) { int z = i.pre_select(&fd_read_set, &fd_write_set); n = std::max(n, z); } for (auto& i : lt) { FD_SET(i.s(), &fd_read_set); n = std::max<int>(n, i.s()); } for (auto& i : lu) { FD_SET(i.s(), &fd_read_set); n = std::max<int>(n, i.s()); } timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; if (select(n + 1, &fd_read_set, &fd_write_set, &fd_except_set, &tv) == SOCKET_ERROR) std::cerr << "select failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; else { m_time = ::time(NULL); for (auto& i : lt) { if (FD_ISSET(i.s(), &fd_read_set)) accept(i.s()); } for (auto& i : lu) { if (FD_ISSET(i.s(), &fd_read_set)) Ctransaction(i.s()).recv(); } for (auto i = m_connections.begin(); i != m_connections.end(); ) { if (i->post_select(&fd_read_set, &fd_write_set)) i = m_connections.erase(i); else i++; } } #endif if (srv_time() - m_read_config_time > m_config.m_read_config_interval) read_config(); else if (srv_time() - m_clean_up_time > m_config.m_clean_up_interval) clean_up(); else if (srv_time() - m_read_db_torrents_time > m_config.m_read_db_interval) read_db_torrents(); else if (srv_time() - m_read_db_users_time > m_config.m_read_db_interval) read_db_users(); else if (m_config.m_write_db_interval && srv_time() - m_write_db_torrents_time > m_config.m_write_db_interval) write_db_torrents(); else if (m_config.m_write_db_interval && srv_time() - m_write_db_users_time > m_config.m_write_db_interval) write_db_users(); } write_db_torrents(); write_db_users(); unlink(m_config.m_pid_file.c_str()); return 0; }