File: client.cc

package info (click to toggle)
golang-github-google-certificate-transparency 0.0~git20160709.0.0f6e3d1~ds1-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster
  • size: 5,676 kB
  • sloc: cpp: 35,278; python: 11,838; java: 1,911; sh: 1,885; makefile: 950; xml: 520; ansic: 225
file content (116 lines) | stat: -rw-r--r-- 2,853 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "client/client.h"

#include <arpa/inet.h>
#include <glog/logging.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/socket.h>
#include <unistd.h>

#ifdef __MACH__
// does not exist on MacOS
#define MSG_NOSIGNAL 0
#endif

using std::string;

Client::Client(const string& server, const string& port)
    : server_(server), port_(port), fd_(-1) {
}

Client::~Client() {
  Disconnect();
}

bool Client::Connect() {
  CHECK(!Connected());

  static const addrinfo server_addr_hints = {
    AI_ADDRCONFIG, /* ai_flags */
    AF_UNSPEC,     /* ai_family */
    SOCK_STREAM,   /* ai_socktype */
    IPPROTO_TCP    /* ai_protocol */
  };

  struct addrinfo* server_addr;

  const int ret = getaddrinfo(server_.c_str(), port_.c_str(),
                              &server_addr_hints, &server_addr);
  CHECK_EQ(0, ret) << "Invalid server address '" << server_
                   << "' and/or port '" << port_ << "': "
                   << gai_strerror(ret);

  bool is_connected = false;
  while (!is_connected && server_addr != NULL) {
    fd_ = socket(server_addr->ai_family,
                 server_addr->ai_socktype,
                 server_addr->ai_protocol);
    PCHECK(fd_ >= 0) << "Socket creation failed";

    if (connect(fd_, server_addr->ai_addr, server_addr->ai_addrlen) == 0) {
      is_connected = true;
    } else {
      server_addr = server_addr->ai_next; // Try next address
    }
  }
  freeaddrinfo(server_addr);

  if (!is_connected) {
    PLOG(ERROR) << "Connection to [" << server_ << "]:" << port_ << " failed";
    Disconnect();
    return false;
  }
  LOG(INFO) << "Connected to [" << server_ << "]:" << port_;
  return true;
}

bool Client::Connected() const {
  return fd_ > 0;
}

void Client::Disconnect() {
  if (fd_ > 0) {
    close(fd_);
    LOG(INFO) << "Disconnected from [" << server_ << "]:" << port_;
    fd_ = -1;
  }
}

bool Client::Write(const string& data) {
  CHECK(Connected());
  int n = send(fd_, data.data(), data.length(), MSG_NOSIGNAL);
  if (n <= 0) {
    PCHECK(errno == EPIPE) << "Send failed";
    LOG(ERROR) << "Remote server closed the connection.";
    Disconnect();
    return false;
  }

  CHECK_EQ(data.length(), (unsigned)n);

  VLOG(1) << "wrote " << data.length() << " bytes";
  return true;
}

bool Client::Read(size_t length, string* result) {
  CHECK(Connected());
  char* buf = new char[length];
  for (size_t offset = 0; offset < length;) {
    int n = recv(fd_, buf + offset, length - offset, MSG_NOSIGNAL);
    if (n <= 0) {
      PCHECK(errno == EPIPE) << "Read failed";
      LOG(ERROR) << "Remote server closed the connection.";
      Disconnect();
      delete[] buf;
      return false;
    }

    offset += n;
  }
  result->assign(string(buf, length));
  delete[] buf;
  VLOG(1) << "read " << length << " bytes";
  return true;
}