1 # include "ae_protocol.hh"
2 # include "messages.pb.h"
3 
4 # include <giomm.h>
5 # include <string>
6 # include <mutex>
7 # include <iostream>
8 
9 #ifdef ASTROID_WEBEXTENSION
10 
11 # include <boost/log/core.hpp>
12 # include <boost/log/trivial.hpp>
13 # define LOG(x) BOOST_LOG_TRIVIAL(x)
14 # define warn warning
15 
16 #else
17 
18 # include "astroid.hh"
19 
20 #endif
21 
22 namespace Astroid {
23 
24   const char * AeProtocol::MessageTypeStrings[] = {
25     "Debug",
26     "Ack",
27     "Info",
28     "Page",
29     "State",
30     "Indent",
31     "AllowRemoteImages",
32     "Focus",
33     "Navigate",
34     "Mark",
35     "Hidden",
36     "ClearMessages",
37     "AddMessage",
38     "UpdateMessage",
39     "RemoveMessage",
40   };
41 
42 
send_message(MessageTypes mt,const::google::protobuf::Message & m,Glib::RefPtr<Gio::OutputStream> ostream)43   void AeProtocol::send_message (
44       MessageTypes mt,
45       const ::google::protobuf::Message &m,
46       Glib::RefPtr<Gio::OutputStream> ostream)
47   {
48     std::string o;
49     gsize written = 0;
50     bool  s = false;
51 
52     m.SerializeToString (&o);
53 
54     /* send size of message */
55     gsize sz = o.size ();
56     s = ostream->write_all ((char*) &sz, sizeof(sz), written);
57 
58     /* send message type */
59     s &= ostream->write_all ((char*) &mt, sizeof (mt), written);
60 
61     /* send message */
62     try {
63       s &= ostream->write_all (o, written);
64     } catch (Gio::Error &ex) {
65       LOG (error) << "ae: error: " << ex.what ();
66       throw;
67     }
68     ostream->flush ();
69 
70     if (!s) {
71       LOG (error) << "ae: could not write message!";
72       throw ipc_error ("could not write message.");
73     } else {
74       LOG (debug) << "ae: wrote: " << written << " of " << o.size () << " bytes.";
75     }
76   }
77 
send_message_async(MessageTypes mt,const::google::protobuf::Message & m,Glib::RefPtr<Gio::OutputStream> ostream,std::mutex & m_ostream)78   void AeProtocol::send_message_async (
79       MessageTypes mt,
80       const ::google::protobuf::Message &m,
81       Glib::RefPtr<Gio::OutputStream> ostream,
82       std::mutex &m_ostream)
83   {
84     LOG (debug) << "ae: sending: " << MessageTypeStrings[mt];
85     LOG (debug) << "ae: send (async) waiting for lock";
86     std::lock_guard<std::mutex> lk (m_ostream);
87     send_message (mt, m, ostream);
88     LOG (debug) << "ae: send (async) message sent.";
89   }
90 
send_message_sync(MessageTypes mt,const::google::protobuf::Message & m,Glib::RefPtr<Gio::OutputStream> ostream,std::mutex & m_ostream,Glib::RefPtr<Gio::InputStream> istream,std::mutex & m_istream)91   AstroidMessages::Ack AeProtocol::send_message_sync (
92       MessageTypes mt,
93       const ::google::protobuf::Message &m,
94       Glib::RefPtr<Gio::OutputStream> ostream,
95       std::mutex & m_ostream,
96       Glib::RefPtr<Gio::InputStream> istream,
97       std::mutex & m_istream)
98   {
99     LOG (debug) << "ae: sending: " << MessageTypeStrings[mt];
100     LOG (debug) << "ae: send (sync) waiting for lock..";
101     std::lock_guard<std::mutex> rlk (m_istream);
102     std::lock_guard<std::mutex> wlk (m_ostream);
103     LOG (debug) << "ae: send (sync) lock acquired.";
104 
105     /* send message */
106     send_message (mt, m, ostream);
107 
108     /* read response */
109     LOG (debug) << "ae: send (sync) waiting for ACK..";
110     AstroidMessages::Ack a;
111     a.set_success (false);
112 
113     {
114       std::vector<gchar> msg_str;
115 
116       auto mt = read_message (
117           istream,
118           Glib::RefPtr<Gio::Cancellable> (NULL),
119           msg_str);
120 
121       /* parse message */
122       if (mt != AeProtocol::MessageTypes::Ack) {
123         LOG (debug) << "ae: reader: did not get Ack message back!";
124         return a;
125       }
126 
127       LOG (debug) << "ae: send (sync) ACK received.";
128       a.ParseFromArray (msg_str.data(), msg_str.size());
129     }
130 
131     return a;
132   }
133 
read_message(Glib::RefPtr<Gio::InputStream> istream,Glib::RefPtr<Gio::Cancellable> reader_cancel,std::vector<gchar> & buffer)134   AeProtocol::MessageTypes AeProtocol::read_message (
135       Glib::RefPtr<Gio::InputStream> istream,
136       Glib::RefPtr<Gio::Cancellable> reader_cancel,
137       std::vector<gchar> &buffer)
138   {
139     gsize read = 0;
140     bool  s    = false;
141 
142     /* read message size */
143     gsize msg_sz = 0;
144     s = istream->read_all ((char *) &msg_sz, sizeof (msg_sz), read, reader_cancel);
145 
146     if (!s || read != sizeof (msg_sz)) {
147       throw ipc_error ("could not read message size");
148     }
149 
150     if (msg_sz > AeProtocol::MAX_MESSAGE_SZ) {
151       throw ipc_error ("message exceeds maximum size.");
152     }
153 
154     AeProtocol::MessageTypes mt;
155     s = istream->read_all ((char*) &mt, sizeof (mt), read, reader_cancel);
156 
157     if (!s || read != sizeof (mt)) {
158       throw ipc_error ("could not read message type");
159     }
160 
161     /* read message */
162     buffer.resize (msg_sz);
163     try {
164       s = istream->read_all (buffer.data(), msg_sz, read, reader_cancel);
165     } catch (Gio::Error &ex) {
166       LOG (error) << "ae: error (read): " << ex.code() << ", " <<  ex.what ();
167       throw;
168     }
169 
170     if (!s || read != msg_sz) {
171       LOG (error) << "reader: error while reading message (size: " << msg_sz << ")";
172       throw ipc_error ("could not read message");
173     }
174     return mt;
175   }
176 
177 
178   /***************
179    * Exceptions
180    ***************/
181 
ipc_error(const char * w)182   AeProtocol::ipc_error::ipc_error (const char * w) : runtime_error (w)
183   {
184   }
185 }
186 
187