bool Thread::start() { int thread_create_status = pthread_create(&(this->thread), NULL, Thread::_thread_start, this); EPYX_ASSERT(thread_create_status == 0); EPYX_ASSERT(this->thread != 0); return true; }
int UDPSocket::recv(void * data, int size) { int bytes; struct sockaddr_storage saddr; socklen_t length = sizeof (saddr); EPYX_ASSERT(data != NULL); EPYX_ASSERT(this->sock >= 0); bytes = ::recvfrom(this->sock, data, size, 0, (struct sockaddr *) &saddr, &length); // TODO: Implement status error (eg. Conn closed, ...) if (bytes < 0) throw ErrException("UDPSocket", "recvfrom"); if (bytes == 0) { //Socket is now closed EPYX_VERIFY(sock < 0); return 0; } /** * recv doesn't set the after-the-last byte to zero. We must do it to * avoid some issues. * (writing into a prefilled longer data buffer f***s everything up) */ if (bytes < size) ((char*) data)[bytes] = 0; lastRecvAddr = SockAddress((const sockaddr *) &saddr); return bytes; }
/** * Send bytes through the network * return: number of sent bytes */ int TCPSocket::send(const void *data, int size) { int bytes; EPYX_ASSERT(data != NULL); if (!this->isConnected) this->connect(); EPYX_ASSERT(this->sock >= 0); EPYX_ASSERT(this->isConnected); bytes = ::send(this->sock, data, size, 0); // TODO: Implement status error (ex. Conn closed, ...) if (bytes == -1) throw ErrException("Socket", "send"); return bytes; }
bool Socket::sendAll(const void *data, int size) { int sentBytes; EPYX_ASSERT(data != NULL); while (size > 0) { sentBytes = this->send(data, size); if (!sentBytes) { log::error << "Socket::sendAll was unable to send " << size << " bytes" << log::endl; return false; } EPYX_ASSERT(sentBytes <= size); size -= sentBytes; } return true; }
N2npNodeId LocalRelay::attachNode(LocalNode *node) { std::string nodeName; // Make this thread-safe this->nodesMutex.lock(); try { // Compute a new Unique ID std::ostringstream nodeNameStream; nodeNameStream << (++this->lastNodeId); nodeName = nodeNameStream.str(); } catch (Exception e) { this->nodesMutex.unlock(); throw e; } this->nodesMutex.unlock(); N2npNodeId nodeId(nodeName.c_str(), this->addr); // This may not happen, as this is an auto-increment index EPYX_ASSERT(this->nodes.count(nodeName) == 0); this->nodesMutex.lock(); this->nodes.insert(make_pair(nodeName, node)); this->nodesMutex.unlock(); return nodeId; }
struct timeval Timeout::remainingTimeval() const { struct timeval tv; int gettimeofday_status = gettimeofday(&tv, NULL); EPYX_ASSERT(gettimeofday_status == 0); if (tv.tv_sec > maxTime.tv_sec) { // Timeout in seconds tv.tv_sec = 0; tv.tv_usec = 0; return tv; } tv.tv_sec = maxTime.tv_sec - tv.tv_sec; if (tv.tv_usec > maxTime.tv_usec) { if (tv.tv_sec == 0) { // Timeout in microseconds tv.tv_usec = 0; return tv; } // Time difference with a reminder tv.tv_sec--; tv.tv_usec = 1000000 + maxTime.tv_usec - tv.tv_usec; } else { tv.tv_usec = maxTime.tv_usec - tv.tv_usec; } return tv; }
IpAddress::IpAddress(const struct sockaddr *saddr) { EPYX_ASSERT(saddr != NULL); char ipBuffer[INET6_ADDRSTRLEN + 1]; if (saddr->sa_family == AF_INET) { // IPv4 struct sockaddr_in *ipv4 = (struct sockaddr_in *) saddr; inet_ntop(AF_INET, &(ipv4->sin_addr), ipBuffer, sizeof (ipBuffer)); this->ip.assign(ipBuffer); this->ipVersion = 4; } else if (saddr->sa_family == AF_INET6) { // IPv6 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) saddr; inet_ntop(AF_INET6, &(ipv6->sin6_addr), ipBuffer, sizeof (ipBuffer)); this->ip.assign(ipBuffer); this->ipVersion = 6; } else { log::fatal << "You have just invented a new IP version " \ << "without giving me information about how to handle it\n" \ << "The version is: " << saddr->sa_family << "\n" \ << "IPv4 is: " << AF_INET << "\n" \ << "IPv6 is: " << AF_INET6 \ << log::endl; throw FailException("IpAddress", "Bad IP Version"); } }
bool Socket::recvBytes(byte_str *data, int size) { EPYX_ASSERT(data != NULL); std::unique_ptr<byte[]> bytes(new byte[size]); if (!this->recvAll(bytes.get(), size)) return false; data->assign(bytes.get()); return true; }
bool Socket::recvAll(void *data, int size) { int recvBytes; EPYX_ASSERT(data != NULL); // TODO: stop on feof ! while (size > 0) { recvBytes = this->recv(data, size); if (!recvBytes) { log::error << "Socket::recvAll was unable to receive " << size << " bytes" << log::endl; return false; } EPYX_ASSERT(recvBytes <= size); size -= recvBytes; } return true; }
bool Server::_internal_bind(int socktype) { //EPYX_ASSERT(port < 65536); char charport[10]; struct addrinfo hints, *addrAll, *pai; int status, flag; // Convert port to char* to find address hints snprintf(charport, sizeof(charport), "%u", port); memset(&hints, 0, sizeof hints); // AF_INET or AF_INET6 to force IP version hints.ai_family = AF_UNSPEC; // SOCK_STREAM (TCP) or SOCK_DGRAM (UDP) hints.ai_socktype = socktype; // Server = passive hints.ai_flags = AI_PASSIVE; status = ::getaddrinfo(NULL, charport, &hints, &addrAll); if (status != 0) { log::fatal << "getaddrinfo error " << status << ": " << gai_strerror(status) << log::endl; throw FailException("TCPServer::bind", "getaddrinfo error"); } // getaddrinfo() returns a list of address structures. // Try each address until we successfully bind. for (pai = addrAll; pai != NULL; pai = pai->ai_next) { // Create a new socket this->sockfd = ::socket(pai->ai_family, pai->ai_socktype, pai->ai_protocol); if (this->sockfd == -1) continue; // Allow reusing the address (ignore failure) flag = 1; setsockopt(this->sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)); // Bind to a listening address/port status = ::bind(this->sockfd, pai->ai_addr, pai->ai_addrlen); if (status == 0) { // Success : remember used address this->address = Address(pai->ai_addr); break; } log::warn << "bind(" << Address(pai->ai_addr) << "): " << log::errstd << log::endl; // Close socket if bind fails ::close(this->sockfd); this->sockfd = -1; } // Free results freeaddrinfo(addrAll); if (pai == NULL) { log::debug << "Nowhere to bind." << log::endl; return false; } // Now there is a socket, listen to nbConn connections EPYX_ASSERT(sockfd >= 0); return true; }
void Thread::term() { if (this->thread != 0) { int thread_cancel_status = pthread_cancel(this->thread); // Thread may have disappeared EPYX_ASSERT(thread_cancel_status == 0 || thread_cancel_status == ESRCH); this->thread = 0; } }
bool Timeout::hasExpired() const { struct timeval tv; int gettimeofday_status = gettimeofday(&tv, NULL); EPYX_ASSERT(gettimeofday_status == 0); return (tv.tv_sec > maxTime.tv_sec) || (tv.tv_sec == maxTime.tv_sec && tv.tv_usec > maxTime.tv_usec); }
Timeout::Timeout(unsigned int ms) { struct timeval tv; int gettimeofday_status = gettimeofday(&tv, NULL); EPYX_ASSERT(gettimeofday_status == 0); long usec = tv.tv_usec + (1000 * ms); maxTime.tv_usec = usec % 1000000; maxTime.tv_sec = tv.tv_sec + (usec / 1000000); }
/** * Receive some bytes from the network in a buffer * @data: buffer pointer * @size: buffer size * return: number of bytes received */ int TCPSocket::recv(void *data, int size) { int bytes; EPYX_ASSERT(data != NULL); EPYX_ASSERT(this->sock >= 0); EPYX_ASSERT(this->isConnected); bytes = ::recv(this->sock, data, size, 0); // TODO: Implement status error (eg. Conn closed, ...) if (bytes == -1) throw ErrException("Socket", "recv"); /** * recv doesn't set the after-the-last byte to zero. We must do it to * avoid some issues. * (writing into a prefilled longer data buffer f***s everything up) */ if (bytes < size) ((char*) data)[bytes] = 0; return bytes; }
int main(){ std::string msgName; char message[MAXLENGTH]; Epyx::Thread::init(); Epyx::log::init(Epyx::log::CONSOLE, ""); try { Epyx::GTTParser myParser; // TODO: Use argc/argv to get msg.txt path std::ifstream msgList("msg.txt"); if(!msgList) { Epyx::log::fatal << "Please provide `msg.txt' to indicate all filenames of messages" << Epyx::log::endl; throw Epyx::FailException("testParser", "No message list found"); } while (!msgList.eof()) { getline(msgList, msgName); // Remove space characters Epyx::String::trim(msgName); if (msgName.empty()) continue; Epyx::log::debug << "Read message `" << msgName << "'" << Epyx::log::endl; std::ifstream msgInput(msgName.c_str(), std::ios_base::in|std::ios_base::binary); if(!msgInput){ Epyx::log::fatal << "Unable to read `" << msgName << "'" << Epyx::log::endl; throw Epyx::FailException("testParser", "Message error"); } while (!msgInput.eof()) { msgInput.read(message, sizeof message); int size = msgInput.gcount(); if (size > 0) myParser.eat(message, size); else { // A reading probleme MUST be because end of file happens EPYX_ASSERT(msgInput.eof()); } Epyx::GTTPacket *pac; while((pac = myParser.getPacket()) != NULL){ Epyx::log::info << "here comes one packet:\n" << *pac << Epyx::log::endl; } } msgInput.close(); } msgList.close(); } catch (Epyx::Exception e) { Epyx::log::fatal << e << Epyx::log::endl; } Epyx::log::flushAndQuit(); return 0; }
void IpAddress::getSockAddr(struct sockaddr *saddr, unsigned short port) const { EPYX_ASSERT(saddr != NULL); EPYX_ASSERT(this->ipVersion > 0); if (this->ipVersion == 4) { // IPv4 struct sockaddr_in *ipv4 = (struct sockaddr_in *) saddr; memset(&(ipv4->sin_zero), 0, sizeof (ipv4->sin_zero)); ipv4->sin_family = AF_INET; inet_pton(AF_INET, ip.c_str(), &(ipv4->sin_addr)); ipv4->sin_port = htons(port); } else if (this->ipVersion == 6) { // IPv6 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) saddr; ipv6->sin6_family = AF_INET6; ipv6->sin6_flowinfo = 0; ipv6->sin6_scope_id = 0; inet_pton(AF_INET6, ip.c_str(), &(ipv6->sin6_addr)); ipv6->sin6_port = htons(port); } else { throw FailException("IpAddress", "Bad IP Version"); } }
void Socket::updateLocalAddress() { EPYX_ASSERT(sock >= 0); struct sockaddr_storage saddr; socklen_t saddr_len = sizeof (saddr); if (::getsockname(sock, (struct sockaddr *) &saddr, &saddr_len) < 0) { log::warn << "Socket::updateLocalAddress: getsockname error " << log::errstd << log::endl; // Do nothing return; } // Update address localAddress = SockAddress((struct sockaddr *) &saddr); }
void* Thread::_thread_start(void *arg) { try { // Call Thread::run() Epyx::Thread *self = (Epyx::Thread*) arg; EPYX_ASSERT(self != NULL); Thread::setName(self->name); self->run(); } catch (std::exception& e) { log::fatal << "Thread exception !" << log::endl; log::fatal << e.what() << log::endl; } return NULL; }
TCPServer::TCPServer(const SockAddress& addr, unsigned int nbConn) :Server(addr) { if (!this->_internal_bind(SOCK_STREAM)) return; // Now there is a socket, listen to nbConn connections EPYX_ASSERT(sockfd >= 0); int status = listen(sockfd, nbConn); if (status < 0) { log::error << "listen: " << log::errstd << log::endl; this->close(); return; } }
void* Thread::_thread_start(void *arg) { try { // Call Thread::run() Epyx::Thread *self = (Epyx::Thread*) arg; EPYX_ASSERT(self != NULL); detail::thread_infos->reset(self->info); self->run(); } catch (Exception e) { log::fatal << "Thread exception !" << log::endl; log::fatal << e << log::endl; } return NULL; }
void Thread::setName(const std::string name, int id) { //Set up oly once the thread info for this thread EPYX_ASSERT(info == NULL); info = new detail::ThreadInfo(); // Copy name if (id != -1) { std::ostringstream str; str << name << " " << id; info->name = str.str(); } else { info->name = name; } }
int UDPSocket::send(const void *data, int size) { int bytes; struct sockaddr_storage saddr; EPYX_ASSERT(data != NULL); // Create a new socket if it does not exist if (sock < 0) { this->create(); } address.getSockAddr((struct sockaddr *) &saddr); bytes = ::sendto(sock, data, size, 0, (const struct sockaddr *) &saddr, sizeof (saddr)); if (localAddress.empty()) this->updateLocalAddress(); // TODO: Implement status error (ex. Conn closed, ...) if (bytes < 0) throw ErrException("UDPSocket", "sendto"); return bytes; }
void run() { EPYX_ASSERT(sock != NULL && srv != NULL); try { // Call real function srv->runSocket(*sock); log::debug << "Client terminated (was " << sock->getAddress() << ")" << log::endl; delete sock; sock = NULL; } catch (Exception e) { log::error << "Error from " << sock->getAddress() << " : " << e << log::endl; } // Close socket delete sock; // Yes, we can do it ! // FIXME: change this ! delete this; }
void GTTParser::eat(const char *data, long size) { EPYX_ASSERT(data != NULL && size > 0); // Append data to reminded if (reminded != NULL) { char *tmp = new char[remindedSize + size + 1]; memcpy(tmp, reminded, remindedSize); memcpy(tmp + remindedSize, data, size); delete[] reminded; reminded = tmp; remindedSize += size; } else { reminded = new char[size + 1]; remindedSize = size; memcpy(reminded, data, size); } // Add a zero at the end to be sure string terminates reminded[remindedSize] = 0; }
bool NetSelectSocket::read() { EPYX_ASSERT(sock); const int size = 4096; byte data[size]; int recvSize = sock->recv(data, size); // Quit on End-Of-File if (recvSize == 0) return false; // Eat data try { this->eat(byte_str(data, recvSize)); } catch (MinorException e) { log::error << e << log::endl; log::error << "Closing socket to " << sock->getAddress() << " due to an exception" << log::endl; return false; } return sock->isOpened(); }
void Thread::term() { int thread_cancel_status = pthread_cancel(this->thread); EPYX_ASSERT(thread_cancel_status == 0); this->thread = 0; }
void Thread::wait() { EPYX_ASSERT(this->thread != 0); int thread_join_status = pthread_join(this->thread, NULL); EPYX_ASSERT(thread_join_status == 0); }
const std::string& Thread::getThisName() { EPYX_ASSERT(info != NULL); return info->name; }
const std::shared_ptr<Socket>& NetSelectSocket::socket() const { EPYX_ASSERT(sock); return sock; }
int NetSelectSocket::getFileDescriptor() const { EPYX_ASSERT(sock); return sock->getFd(); }