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 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 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 TCPServerThread::run() { int newfd = -1; struct sockaddr_storage clientAddr; socklen_t clientAddrLen; Socket *newSock = NULL; _TCPSocketThread *sthread = NULL; int spawnId = 1; // Bind if no socket available if (this->sockfd < 0 && !this->bind()) throw FailException("TCPServer::run", "Unable to bind"); EPYX_ASSERT(this->sockfd >= 0); log::debug << "Listening on " << this->address << log::endl; try { this->running = true; while (this->running && this->sockfd >= 0) { clientAddrLen = sizeof clientAddr; newfd = ::accept(this->sockfd, (struct sockaddr*)&clientAddr, &clientAddrLen); // If this thread was not killed, return if (!this->running || this->sockfd < 0) { ::shutdown(newfd, SHUT_RDWR); ::close(newfd); newfd = -1; break; } if (newfd == -1) throw ErrException("TCPServer::run", "accept"); // Encapsulate socket try { newSock = new TCPSocket(newfd, Address((struct sockaddr*)&clientAddr)); } catch (Exception e) { log::error << "Unable to setup the link:\n" << e << log::endl; if (newSock) delete newSock; else if (newfd >= 0) { // newfd is managed by newSock ::close(newfd); } newSock = NULL; } // Make newfd variable invalid newfd = -1; if (newSock != NULL) { try { sthread = new _TCPSocketThread(this, newSock, this->getThisName(), spawnId++); sthread->start(); } catch (Exception e) { log::error << e << log::endl; log::error << "Unable to start a thread" << log::endl; if (sthread != NULL) delete sthread; delete newSock; } // DO NOT delete newSock nor srun as they are owned by an other thread newSock = NULL; sthread = NULL; } } } catch (Exception e) { log::error << e << log::endl; log::error << "Arg ! An exception killed me !" << log::endl; if (newSock) delete newSock; } log::debug << "Clean exit on " << this->address << log::endl; }
/** * @brief sInternal function, only called by GTTParser::getPacket * * @throw ParserException on errors */ bool GTTParser::processChar(char c) { // Create a nw packet if we does not have anyone yet if (currentPkt == NULL) currentPkt = new GTTPacket(); switch(currentType) { case start: // Start a new packet if (!isupper(c)) throw ParserException("protocol name should begin with capital letters"); currentString = c; currentType = protocol_name; flagType = other; break; case protocol_name: if(isupper(c) || isdigit(c) || (c == '_')) { currentString += c; } else if(c == ' ') { currentPkt->protocol = currentString; currentString = ""; currentType = method; flagType = start; } else throw ParserException("protocol name should continue with [A-Z0-9]* or end with a space"); break; case method: if (flagType == start){ if (!isupper(c)) throw ParserException("method should begin with capital letters"); currentString = c; flagType = other; } else if (isupper(c) || isdigit(c) || (c == '_')) currentString += c; else if (c == '\r') { currentPkt->method = currentString; currentString = ""; currentType = method_line; } else throw ParserException("method should continue with [A-Z0-9_] or end with CRLF"); break; case method_line: if (c != '\n') throw ParserException("newline should be CRLF"); currentType = flag_name; flagType = start; break; case flag_name: if(flagType == start){ if (isalpha(c)) currentString = c; else if (c == '\r') { // New line at the end of the headers currentType = newline; } else throw ParserException("flag_name should begin with [a-zA-Z] or we should add newline to end the header"); flagType = other; } else if(isalnum(c) || (c == '_') || (c == '-')) { currentString += c; } else if(c == ':') { currentFlagName = currentString; currentString = ""; currentType = flag_indicator; /* if(!strcasecmp(currentString.c_str(), "content-length")) { if(currentPkt->size > 0) throw FailException("Parser", "content-length flag has already appeared"); else hasBody=true; }*/ } else throw ParserException("flag_name should continue with [a-zA-Z0-9_-] or end with :"); break; case flag_indicator: // Skip spaces if(c == ' ') break; /* Walk through */ case flag_value: if (32 <= c && c < 126) { // Printable ASCII characters currentString += c; } else if(c == '\r') { if(!strcasecmp(currentFlagName.c_str(), "content-length")) { if(currentPkt->size > 0) throw FailException("Parser", "content-length flag has already appeared"); currentPkt->size = String::toInt(currentString.c_str()); if (currentPkt->size <= 0) throw FailException("Parser", "not valid body size, body size should be a positive integer"); currentPkt->body = new char[currentPkt->size]; } else currentPkt->headers[currentFlagName] = currentString; currentString = ""; currentFlagName = ""; currentType = flag_line; } else throw ParserException("flag_value should consist of printable characters or just end with CRLF"); break; case flag_line: if (c != '\n') throw ParserException("newline should be CRLF"); currentType = flag_name; flagType = start; break; case newline: if (c != '\n') throw ParserException("newline should be CRLF"); if (currentPkt->size == 0) { // No body return true; } bodyCounter = 0; currentType = body; break; case body: EPYX_ASSERT(bodyCounter < currentPkt->size); currentPkt->body[bodyCounter] = c; bodyCounter ++; if (bodyCounter == currentPkt->size) { // Return there is a new packet return true; } break; case other: throw ParserException("Unreachable state"); } return false; }