aboutsummaryrefslogtreecommitdiff
path: root/openssl/protocol.cxx
blob: e74b35e7f595491e77f36ebaa17d4c8fad417614 (plain)
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// file      : openssl/protocol.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#include <openssl/protocol.hxx>

#include <sys/un.h>     // sockaddr_un
#include <sys/types.h>
#include <sys/socket.h>

#include <cstring> // strcpy()

namespace openssl
{
  using namespace std;

  auto_fd
  connect (const path& p)
  {
    auto_fd sock (socket (AF_UNIX, SOCK_STREAM, 0));

    if (sock.get () == -1)
      throw_system_ios_failure (errno);

    struct sockaddr_un addr;
    memset (&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;

    if (p.string ().size () >= sizeof (addr.sun_path))
      throw_generic_ios_failure (ENAMETOOLONG);

    strcpy (addr.sun_path, p.string ().c_str ());

    if (connect (sock.get (),
                 reinterpret_cast<sockaddr*> (&addr),
                 sizeof (addr)) == -1)
      throw_system_ios_failure (errno);

    return sock;
  }

  ostream&
  operator<< (ostream& os, const request& r)
  {
    // Write the header: command, arguments count and input data length.
    //
    os << r.cmd << ' ' << r.args.size () << ' ' << r.input.size () << '\n';

    // Write the arguments.
    //
    for (const string& a: r.args)
      os.write (a.c_str (), a.size () + 1); // Includes the trailing '\0';

    // Write the input data.
    //
    os.write (r.input.data (), r.input.size ());
    return os << flush;
  }

  istream&
  operator>> (istream& is, request& r)
  {
    // Read the header: command, arguments count and input data length.
    //
    size_t na, ni;
    is >> r.cmd >> na >> ni;

    if (is.get () != '\n')
    {
      is.setstate (istream::failbit);
      return is;
    }

    // Read the arguments.
    //
    for (string l; na != 0 && !eof (getline (is, l, '\0')); --na)
      r.args.push_back (move (l));

    if (na != 0)
    {
      is.setstate (istream::failbit);
      return is;
    }

    // Read the input data.
    //
    r.input.resize (ni);
    return is.read (r.input.data (), ni);
  }

  ostream&
  operator<< (ostream& os, const response& r)
  {
    // Write the header: status and output/error data lengths.
    //
    os << r.status << ' ' << r.output.size () << ' ' << r.error.size ()
       << '\n';

    // Write the output and error data.
    //
    os.write (r.output.data (), r.output.size ());
    os.write (r.error.data (), r.error.size ());
    return os << flush;
  }

  istream&
  operator>> (istream& is, response& r)
  {
    // Read the header: status and output/error data lengths.
    //
    size_t no, ne;
    is >> r.status >> no >> ne;

    if (is.get () != '\n')
    {
      is.setstate (istream::failbit);
      return is;
    }

    // Read the output data.
    //
    r.output.resize (no);
    is.read (r.output.data (), no);

    // Read the error (text) data.
    //
    for (r.error.reserve (ne); ne != 0; --ne)
      r.error.push_back (is.get ());

    return is;
  }
}