#include #include #include #include #include #include "stg/common.h" #include "proto.h" int WaitPacket(int sd, int timeout) { fd_set rfds; FD_ZERO(&rfds); FD_SET(sd, &rfds); struct timeval tv; tv.tv_sec = timeout; tv.tv_usec = 0; int res = select(sd + 1, &rfds, NULL, NULL, &tv); if (res == -1) // Error { if (errno != EINTR) { printfd(__FILE__, "Error on select: '%s'\n", strerror(errno)); } return -1; } if (res == 0) // Timeout { return 0; } return 1; } PROTO::PROTO(const std::string & server, uint16_t port, uint16_t localPort, int to) : running(false), stopped(true), timeout(to) { uint32_t ip = inet_addr(server.c_str()); if (ip == INADDR_NONE) { struct hostent * hePtr = gethostbyname(server.c_str()); if (hePtr) { ip = *((uint32_t *)hePtr->h_addr_list[0]); } else { errorStr = "Unknown host: '"; errorStr += server; errorStr += "'"; printfd(__FILE__, "PROTO::PROTO() - %s\n", errorStr.c_str()); throw std::runtime_error(errorStr); } } sock = socket(AF_INET, SOCK_DGRAM, 0); localAddr.sin_family = AF_INET; localAddr.sin_port = htons(localPort); localAddr.sin_addr.s_addr = inet_addr("0.0.0.0"); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(port); serverAddr.sin_addr.s_addr = ip; unsigned char key[IA_PASSWD_LEN]; memset(key, 0, IA_PASSWD_LEN); strncpy(reinterpret_cast(key), "pr7Hhen", 8); Blowfish_Init(&ctx, key, IA_PASSWD_LEN); processors["CONN_SYN_ACK"] = &PROTO::CONN_SYN_ACK_Proc; processors["ALIVE_SYN"] = &PROTO::ALIVE_SYN_Proc; processors["DISCONN_SYN_ACK"] = &PROTO::DISCONN_SYN_ACK_Proc; processors["FIN"] = &PROTO::FIN_Proc; processors["INFO"] = &PROTO::INFO_Proc; // ERR_Proc will be handled explicitly } PROTO::~PROTO() { close(sock); } void * PROTO::Runner(void * data) { PROTO * protoPtr = static_cast(data); protoPtr->Run(); } bool PROTO::Start() { stopped = false; running = true; if (pthread_create(&tid, NULL, &Runner, NULL)) { errorStr = "Failed to create listening thread: '"; errorStr += strerror(errno); errorStr += "'"; printfd(__FILE__, "PROTO::Start() - %s\n", errorStr.c_str()); return false; } return true; } bool PROTO::Stop() { running = false; int time = 0; while (!stopped && time < timeout) { struct timespec ts = {1, 0}; nanosleep(&ts, NULL); ++time; } if (!stopped) { errorStr = "Failed to stop listening thread - timed out"; printfd(__FILE__, "PROTO::Stop() - %s\n", errorStr.c_str()); return false; } if (pthread_join(tid, NULL)) { errorStr = "Failed to join listening thread after stop: '"; errorStr += strerror(errno); errorStr += "'"; printfd(__FILE__, "PROTO::Stop() - %s\n", errorStr.c_str()); return false; } return true; } bool PROTO::Connect(const std::string & login) { std::map::const_iterator it; it = users.find(login); if (it == users.end()) return false; // Do something return true; } bool PROTO::Disconnect(const std::string & login) { std::map::const_iterator it; it = users.find(login); if (it == users.end()) return false; // Do something return true; } void PROTO::Run() { while (running) { int res = WaitPacket(sock, timeout); if (res < 0) break; if (!running) break; if (res) RecvPacket(); } stopped = true; } bool PROTO::RecvPacket() { struct sockaddr_in addr; socklen_t fromLen = sizeof(addr); char buffer[2048]; int res = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, &fromLen); if (res == -1) return res; return HandlePacket(buffer); } bool PROTO::HandlePacket(char * buffer) { if (strcmp(buffer + 4 + sizeof(HDR_8), "ERR")) { return ERR_Proc(buffer); } std::string packetName(buffer + 12); std::map::const_iterator it; it = processors.find(packetName); if (it != processors.end()) return (this->*it->second)(buffer); return false; }