IpPort getIpPortFromSockAddr(const SockAddr &sa){ const int family = sa.getFamily(); if(family == AF_INET){ if(sa.getSize() < sizeof(::sockaddr_in)){ LOG_POSEIDON_WARNING("Invalid IPv4 SockAddr: size = ", sa.getSize()); DEBUG_THROW(Exception, sslit("Invalid IPv4 SockAddr")); } char ip[INET_ADDRSTRLEN]; const char *const str = ::inet_ntop(AF_INET, &static_cast<const ::sockaddr_in *>(sa.getData())->sin_addr, ip, sizeof(ip)); if(!str){ DEBUG_THROW(SystemException); } return IpPort(SharedNts(str), loadBe(static_cast<const ::sockaddr_in *>(sa.getData())->sin_port)); } else if(family == AF_INET6){ if(sa.getSize() < sizeof(::sockaddr_in6)){ LOG_POSEIDON_WARNING("Invalid IPv6 SockAddr: size = ", sa.getSize()); DEBUG_THROW(Exception, sslit("Invalid IPv6 SockAddr")); } char ip[INET6_ADDRSTRLEN]; const char *const str = ::inet_ntop(AF_INET6, &static_cast<const ::sockaddr_in6 *>(sa.getData())->sin6_addr, ip, sizeof(ip)); if(!str){ DEBUG_THROW(SystemException); } return IpPort(SharedNts(str), loadBe(static_cast<const ::sockaddr_in6 *>(sa.getData())->sin6_port)); } LOG_POSEIDON_WARNING("Unknown IP protocol ", family); DEBUG_THROW(Exception, sslit("Unknown IP protocol")); }
boost::shared_ptr<const JobPromise> DnsDaemon::enqueue_for_looking_up(boost::shared_ptr<SockAddr> sock_addr, std::string host, unsigned port){ PROFILE_ME; AUTO(promise, boost::make_shared<JobPromise>()); const AUTO(param, new DnsCallbackParam(STD_MOVE(sock_addr), host, port, promise)); atomic_add(g_pending_callback_count, 1, ATOMIC_RELAXED); // noexcept try { ::sigevent sev; sev.sigev_notify = SIGEV_THREAD; sev.sigev_value.sival_ptr = param; sev.sigev_notify_function = &dns_callback; sev.sigev_notify_attributes = NULLPTR; AUTO(pcb, &(param->cb)); const int gai_code = ::getaddrinfo_a(GAI_NOWAIT, &pcb, 1, &sev); // noexcept if(gai_code != 0){ LOG_POSEIDON_WARNING("DNS failure: gai_code = ", gai_code, ", err_msg = ", ::gai_strerror(gai_code)); DEBUG_THROW(Exception, sslit("DNS failure")); } } catch(...){ atomic_sub(g_pending_callback_count, 1, ATOMIC_RELAXED); // noexcept delete param; throw; } return promise; }
bool SockAddr::isPrivate() const { const int family = getFamily(); if(family == AF_INET){ const AUTO_REF(ip, reinterpret_cast<const unsigned char (&)[4]>( static_cast<const ::sockaddr_in *>(getData())->sin_addr)); if(ip[0] == 0){ // 0.0.0.0/8: 当前网络地址 return true; } else if(ip[0] == 10){ // 10.0.0.0/8: A 类私有地址 return true; } else if(ip[0] == 127){ // 127.0.0.0/8: 回环地址 return true; } else if((ip[0] == 172) && ((ip[1] & 0xF0) == 16)){ // 172.16.0.0/12: B 类私有地址 return true; } else if((ip[0] == 169) && (ip[1] == 254)){ // 169.254.0.0/16: 链路本地地址 return true; } else if((ip[0] == 192) && (ip[1] == 168)){ // 192.168.0.0/16: C 类私有地址 return true; } else if(ip[0] >= 224){ // D 类、E 类地址和广播地址 return true; } return false; } else if(family == AF_INET6){ static const unsigned char ZEROES[16] = { }; const AUTO_REF(ip, reinterpret_cast<const unsigned char (&)[16]>( static_cast<const ::sockaddr_in6 *>(getData())->sin6_addr)); if(std::memcmp(ip, ZEROES, 15) == 0){ if(ip[15] == 0){ // ::/128: 未指定的地址 return true; } if(ip[15] == 1){ // ::1/128: 回环地址 return true; } } else if((std::memcmp(ip, ZEROES, 10) == 0) && (ip[10] == 0xFF) && (ip[11] == 0xFF)){ // IPv4 翻译地址 if(ip[12] == 0){ // 0.0.0.0/8: 当前网络地址 return true; } else if(ip[12] == 10){ // 10.0.0.0/8: A 类私有地址 return true; } else if(ip[12] == 127){ // 127.0.0.0/8: 回环地址 return true; } else if((ip[12] == 172) && ((ip[13] & 0xF0) == 16)){ // 172.16.0.0/12: B 类私有地址 return true; } else if((ip[12] == 169) && (ip[13] == 254)){ // 169.254.0.0/16: 链路本地地址 return true; } else if((ip[12] == 192) && (ip[13] == 168)){ // 192.168.0.0/16: C 类私有地址 return true; } else if(ip[12] >= 224){ // D 类、E 类地址和广播地址 return true; } } else if((ip[0] == 0x01) && (std::memcmp(ip + 1, ZEROES, 7) == 0)){ // 100::/64 黑洞地址 return true; } else if(ip[0] >= 0xFC){ // 私有地址、链路本地地址和广播地址 return true; } return false; } LOG_POSEIDON_WARNING("Unknown IP protocol ", family); DEBUG_THROW(Exception, sslit("Unknown IP protocol")); }
std::size_t CsvParser::seek(std::size_t row){ if((row != static_cast<std::size_t>(-1)) && (row >= m_data.size())){ DEBUG_THROW(Exception, sslit("Row index is out of range")); } const AUTO(oldRow, m_row); m_row = row; return oldRow; }
SslFilterBase::SslFilterBase(Move<UniqueSsl> ssl, int fd) : m_ssl(STD_MOVE(ssl)), m_fd(fd) , m_established(false) { if(!::SSL_set_fd(m_ssl.get(), fd)){ DEBUG_THROW(Exception, sslit("::SSL_set_fd() failed")); } }
int SockAddr::getFamily() const { const AUTO(p, reinterpret_cast<const ::sockaddr *>(m_data)); if(m_size < sizeof(p->sa_family)){ LOG_POSEIDON_ERROR("Invalid SockAddr: size = ", m_size); DEBUG_THROW(Exception, sslit("Invalid SockAddr")); } return p->sa_family; }
SockAddr::SockAddr(const void *data, unsigned size){ if(size > sizeof(m_data)){ LOG_POSEIDON_ERROR("SockAddr size too large: ", size); DEBUG_THROW(Exception, sslit("SockAddr size too large")); } m_size = size; std::memcpy(m_data, data, size); }
long ClientWriter::put_chunked_header(RequestHeaders request_headers){ PROFILE_ME; StreamBuffer data; data.put(get_string_from_verb(request_headers.verb)); data.put(' '); data.put(request_headers.uri); if(!request_headers.get_params.empty()){ data.put('?'); data.put(url_encoded_from_optional_map(request_headers.get_params)); } char temp[64]; const unsigned ver_major = request_headers.version / 10000, ver_minor = request_headers.version % 10000; unsigned len = (unsigned)std::sprintf(temp, " HTTP/%u.%u\r\n", ver_major, ver_minor); data.put(temp, len); AUTO_REF(headers, request_headers.headers); if(!headers.has("Content-Type")){ headers.set(sslit("Content-Type"), "application/x-www-form-urlencoded; charset=utf-8"); } AUTO(transfer_encoding, headers.get("Transfer-Encoding")); AUTO(pos, transfer_encoding.find(';')); if(pos != std::string::npos){ transfer_encoding.erase(pos); } transfer_encoding = to_lower_case(trim(STD_MOVE(transfer_encoding))); if(transfer_encoding.empty() || (transfer_encoding == STR_IDENTITY)){ headers.set(sslit("Transfer-Encoding"), STR_CHUNKED); } else { headers.set(sslit("Transfer-Encoding"), STD_MOVE(transfer_encoding)); } for(AUTO(it, headers.begin()); it != headers.end(); ++it){ data.put(it->first.get()); data.put(": "); data.put(it->second); data.put("\r\n"); } data.put("\r\n"); return on_encoded_data_avail(STD_MOVE(data)); }
bool SockAddr::isIpv6() const { const int family = getFamily(); if(family == AF_INET){ return false; } else if(family == AF_INET6){ return true; } LOG_POSEIDON_WARNING("Unknown IP protocol ", family); DEBUG_THROW(Exception, sslit("Unknown IP protocol")); }
long ClientWriter::put_chunk(StreamBuffer entity){ PROFILE_ME; if(entity.empty()){ LOG_POSEIDON_ERROR("You are not allowed to send an empty chunk"); DEBUG_THROW(BasicException, sslit("You are not allowed to send an empty chunk")); } StreamBuffer chunk; char temp[64]; unsigned len = (unsigned)std::sprintf(temp, "%llx\r\n", (unsigned long long)entity.size()); chunk.put(temp, len); chunk.splice(entity); chunk.put("\r\n"); return on_encoded_data_avail(STD_MOVE(chunk)); }
SockAddr getSockAddrFromIpPort(const IpPort &addr){ ::sockaddr_in sin; if(::inet_pton(AF_INET, addr.ip.get(), &sin.sin_addr) == 1){ sin.sin_family = AF_INET; storeBe(sin.sin_port, addr.port); return SockAddr(&sin, sizeof(sin)); } ::sockaddr_in6 sin6; if(::inet_pton(AF_INET6, addr.ip.get(), &sin6.sin6_addr) == 1){ sin6.sin6_family = AF_INET6; storeBe(sin6.sin6_port, addr.port); return SockAddr(&sin6, sizeof(sin6)); } LOG_POSEIDON_ERROR("Unknown address format: ", addr.ip); DEBUG_THROW(Exception, sslit("Unknown address format")); }
bool TcpServerBase::poll() const { UniqueFile client(::accept(get_fd(), NULLPTR, NULLPTR)); if(!client){ if(errno != EAGAIN){ DEBUG_THROW(SystemException); } return false; } AUTO(session, on_client_connect(STD_MOVE(client))); if(!session){ LOG_POSEIDON_WARNING("on_client_connect() returns a null pointer."); DEBUG_THROW(Exception, sslit("Null client pointer")); } if(m_ssl_factory){ AUTO(ssl, m_ssl_factory->create_ssl()); boost::scoped_ptr<SslFilterBase> filter(new SslFilter(STD_MOVE(ssl), session->get_fd())); session->init_ssl(STD_MOVE(filter)); } session->set_timeout(EpollDaemon::get_tcp_request_timeout()); EpollDaemon::add_session(session); LOG_POSEIDON_INFO("Accepted TCP connection from ", session->get_remote_info()); return true; }
long ClientWriter::put_request(RequestHeaders request_headers, StreamBuffer entity){ PROFILE_ME; StreamBuffer data; data.put(get_string_from_verb(request_headers.verb)); data.put(' '); data.put(request_headers.uri); if(!request_headers.get_params.empty()){ data.put('?'); data.put(url_encoded_from_optional_map(request_headers.get_params)); } char temp[64]; const unsigned ver_major = request_headers.version / 10000, ver_minor = request_headers.version % 10000; unsigned len = (unsigned)std::sprintf(temp, " HTTP/%u.%u\r\n", ver_major, ver_minor); data.put(temp, len); AUTO_REF(headers, request_headers.headers); if(entity.empty()){ headers.erase("Content-Type"); headers.erase("Transfer-Encoding"); if((request_headers.verb == V_POST) || (request_headers.verb == V_PUT)){ headers.set(sslit("Content-Length"), STR_0); } else { headers.erase("Content-Length"); } } else { if(!headers.has("Content-Type")){ headers.set(sslit("Content-Type"), "application/x-www-form-urlencoded; charset=utf-8"); } AUTO(transfer_encoding, headers.get("Transfer-Encoding")); AUTO(pos, transfer_encoding.find(';')); if(pos != std::string::npos){ transfer_encoding.erase(pos); } transfer_encoding = to_lower_case(trim(STD_MOVE(transfer_encoding))); if(transfer_encoding.empty() || (transfer_encoding == STR_IDENTITY)){ headers.set(sslit("Content-Length"), boost::lexical_cast<std::string>(entity.size())); } else { // 只有一个 chunk。 StreamBuffer chunk; len = (unsigned)std::sprintf(temp, "%llx\r\n", (unsigned long long)entity.size()); chunk.put(temp, len); chunk.splice(entity); chunk.put("\r\n0\r\n\r\n"); entity.swap(chunk); } } for(AUTO(it, headers.begin()); it != headers.end(); ++it){ data.put(it->first.get()); data.put(": "); data.put(it->second); data.put("\r\n"); } data.put("\r\n"); data.splice(entity); return on_encoded_data_avail(STD_MOVE(data)); }
void CsvParser::load(const char *file){ LOG_POSEIDON_DEBUG("Loading CSV file: ", file); StreamBuffer buffer; fileGetContents(buffer, file); buffer.put('\n'); std::vector<OptionalMap> data; std::vector<std::vector<std::string> > rows; { std::vector<std::string> row; std::string token; bool first = true; bool inQuote = false; do { char ch = buffer.get(); if(ch == '\r'){ if(buffer.peek() == '\n'){ buffer.get(); } ch = '\n'; } if(first){ first = false; if(ch == '\"'){ inQuote = true; continue; } } if(ch == '\"'){ if(inQuote){ if(buffer.peek() == '\"'){ buffer.get(); token.push_back('\"'); } else { inQuote = false; } continue; } } if(!inQuote){ if((ch == ',') || (ch == '\n')){ std::string trimmed; const std::size_t begin = token.find_first_not_of(" \t\r\n"); if(begin != std::string::npos){ const std::size_t end = token.find_last_not_of(" \t\r\n") + 1; trimmed = token.substr(begin, end - begin); } row.push_back(STD_MOVE(trimmed)); token.clear(); first = true; if(ch == '\n'){ rows.push_back(STD_MOVE(row)); row.clear(); } continue; } } token.push_back(ch); } while(!buffer.empty()); } if(rows.empty() || rows.front().empty()){ LOG_POSEIDON_ERROR("The first line of a CSV file may not be empty."); DEBUG_THROW(Exception, sslit("Bad CSV header")); } const std::size_t columnCount = rows.front().size(); std::vector<SharedNts> keys(columnCount); for(std::size_t i = 0; i < columnCount; ++i){ AUTO_REF(key, rows.front().at(i)); for(std::size_t j = 0; j < i; ++j){ if(keys.at(j) == key){ LOG_POSEIDON_ERROR("Duplicate key: ", key); DEBUG_THROW(Exception, sslit("Duplicate key")); } } keys.at(i).assign(key.c_str()); } for(std::size_t i = 1; i < rows.size(); ++i){ rows.at(i - 1).swap(rows.at(i)); } rows.pop_back(); { std::size_t line = 1; std::size_t i = 0; while(i < rows.size()){ AUTO_REF(row, rows.at(i)); ++line; if((row.size() == 1) && row.front().empty()){ for(std::size_t j = i + 1; j < rows.size(); ++j){ rows.at(j - 1).swap(rows.at(j)); } rows.pop_back(); continue; } if(row.size() != columnCount){ LOG_POSEIDON_ERROR("There are ", row.size(), " column(s) on line ", line, " but there are ", columnCount, " in the header"); DEBUG_THROW(Exception, sslit("Inconsistent CSV column numbers")); } ++i; } } const std::size_t rowCount = rows.size(); data.resize(rowCount); for(std::size_t i = 0; i < rowCount; ++i){ AUTO_REF(row, rows.at(i)); AUTO_REF(map, data.at(i)); for(std::size_t j = 0; j < columnCount; ++j){ map.create(keys.at(j))->second.swap(row.at(j)); } } LOG_POSEIDON_DEBUG("Done loading CSV file: ", file); m_data.swap(data); m_row = static_cast<std::size_t>(-1); }