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