X-Git-Url: https://git.sesse.net/?p=cubemap;a=blobdiff_plain;f=client.cpp;h=77fad722a6ba9881ad44cc1e3c949beba1a580e9;hp=f2d60a62653ea13abad4ff9366e8a2e5fa55ca97;hb=38a2bb28fd8dcb5bb1e0cb56028936a35f20f503;hpb=807a8ae8f6aca56e3e809aa19f4034a323f1b987 diff --git a/client.cpp b/client.cpp index f2d60a6..77fad72 100644 --- a/client.cpp +++ b/client.cpp @@ -1,37 +1,59 @@ +#include #include #include -#include +#include #include #include "client.h" -#include "markpool.h" +#include "log.h" #include "state.pb.h" #include "stream.h" +#ifndef SO_MAX_PACING_RATE +#define SO_MAX_PACING_RATE 47 +#endif + using namespace std; Client::Client(int sock) : sock(sock), - fwmark(0), - connect_time(time(NULL)), state(Client::READING_REQUEST), stream(NULL), - header_or_error_bytes_sent(0), - stream_pos(0) + header_or_short_response_bytes_sent(0), + stream_pos(0), + bytes_sent(0), + bytes_lost(0), + num_loss_events(0) { request.reserve(1024); + if (clock_gettime(CLOCK_MONOTONIC_COARSE, &connect_time) == -1) { + log_perror("clock_gettime(CLOCK_MONOTONIC_COARSE)"); + return; + } + // Find the remote address, and convert it to ASCII. sockaddr_in6 addr; socklen_t addr_len = sizeof(addr); if (getpeername(sock, reinterpret_cast(&addr), &addr_len) == -1) { - perror("getpeername"); + log_perror("getpeername"); remote_addr = ""; + return; + } + + char buf[INET6_ADDRSTRLEN]; + if (IN6_IS_ADDR_V4MAPPED(&addr.sin6_addr)) { + // IPv4 address, really. + if (inet_ntop(AF_INET, &addr.sin6_addr.s6_addr32[3], buf, sizeof(buf)) == NULL) { + log_perror("inet_ntop"); + remote_addr = ""; + } else { + remote_addr = buf; + } } else { - char buf[INET6_ADDRSTRLEN]; if (inet_ntop(addr.sin6_family, &addr.sin6_addr, buf, sizeof(buf)) == NULL) { - perror("inet_ntop"); + log_perror("inet_ntop"); remote_addr = ""; } else { remote_addr = buf; @@ -42,25 +64,28 @@ Client::Client(int sock) Client::Client(const ClientProto &serialized, Stream *stream) : sock(serialized.sock()), remote_addr(serialized.remote_addr()), - connect_time(serialized.connect_time()), + referer(serialized.referer()), + user_agent(serialized.user_agent()), state(State(serialized.state())), request(serialized.request()), - stream_id(serialized.stream_id()), + url(serialized.url()), stream(stream), - header_or_error(serialized.header_or_error()), - header_or_error_bytes_sent(serialized.header_or_error_bytes_sent()), - stream_pos(serialized.stream_pos()) + header_or_short_response(serialized.header_or_short_response()), + header_or_short_response_bytes_sent(serialized.header_or_short_response_bytes_sent()), + stream_pos(serialized.stream_pos()), + bytes_sent(serialized.bytes_sent()), + bytes_lost(serialized.bytes_lost()), + num_loss_events(serialized.num_loss_events()) { - if (stream != NULL && stream->mark_pool != NULL) { - fwmark = stream->mark_pool->get_mark(); - } else { - fwmark = 0; // No mark. - } - if (setsockopt(sock, SOL_SOCKET, SO_MARK, &fwmark, sizeof(fwmark)) == -1) { - if (fwmark != 0) { - perror("setsockopt(SO_MARK)"); + if (stream != NULL) { + if (setsockopt(sock, SOL_SOCKET, SO_MAX_PACING_RATE, &stream->pacing_rate, sizeof(stream->pacing_rate)) == -1) { + if (stream->pacing_rate != ~0U) { + log_perror("setsockopt(SO_MAX_PACING_RATE)"); + } } } + connect_time.tv_sec = serialized.connect_time_sec(); + connect_time.tv_nsec = serialized.connect_time_nsec(); } ClientProto Client::serialize() const @@ -68,22 +93,55 @@ ClientProto Client::serialize() const ClientProto serialized; serialized.set_sock(sock); serialized.set_remote_addr(remote_addr); - serialized.set_connect_time(connect_time); + serialized.set_referer(referer); + serialized.set_user_agent(user_agent); + serialized.set_connect_time_sec(connect_time.tv_sec); + serialized.set_connect_time_nsec(connect_time.tv_nsec); serialized.set_state(state); serialized.set_request(request); - serialized.set_stream_id(stream_id); - serialized.set_header_or_error(header_or_error); - serialized.set_header_or_error_bytes_sent(serialized.header_or_error_bytes_sent()); + serialized.set_url(url); + serialized.set_header_or_short_response(header_or_short_response); + serialized.set_header_or_short_response_bytes_sent(serialized.header_or_short_response_bytes_sent()); serialized.set_stream_pos(stream_pos); + serialized.set_bytes_sent(bytes_sent); + serialized.set_bytes_lost(bytes_lost); + serialized.set_num_loss_events(num_loss_events); return serialized; } + +namespace { + +string escape_string(const string &str) { + string ret; + for (size_t i = 0; i < str.size(); ++i) { + char buf[16]; + if (isprint(str[i]) && str[i] >= 32 && str[i] != '"' && str[i] != '\\') { + ret.push_back(str[i]); + } else { + snprintf(buf, sizeof(buf), "\\x%02x", (unsigned char)str[i]); + ret += buf; + } + } + return ret; +} + +} // namespace ClientStats Client::get_stats() const { ClientStats stats; - stats.stream_id = stream_id; + if (url.empty()) { + stats.url = "-"; + } else { + stats.url = url; + } + stats.sock = sock; stats.remote_addr = remote_addr; + stats.referer = escape_string(referer); + stats.user_agent = escape_string(user_agent); stats.connect_time = connect_time; - stats.bytes_sent = stream_pos; + stats.bytes_sent = bytes_sent; + stats.bytes_lost = bytes_lost; + stats.num_loss_events = num_loss_events; return stats; }