blob: bff1b21df79c026c07bdddd594886c3eec1bff9e [file] [log] [blame]
jat@google.com134be542009-08-03 15:30:11 +00001/*
2 * Copyright 2008 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17#include <cstdio>
18#include <cstdlib>
19#include <cstring>
20#include <cerrno>
21
22#include "Debug.h"
23
24#ifdef _WINDOWS
25#include <winsock2.h>
26#include <ws2tcpip.h>
27#else
28#include <netdb.h>
29#include <sys/socket.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <unistd.h>
33#include <sys/time.h>
34#endif
35#include <time.h>
36
37#include "Platform.h"
38#include "ByteOrder.h"
39
jat@google.com5e86cbd2009-08-22 23:59:24 +000040#include "CheckVersionsMessage.h"
41#include "ProtocolVersionMessage.h"
42#include "ChooseTransportMessage.h"
43#include "SwitchTransportMessage.h"
44#include "FatalErrorMessage.h"
jat@google.com134be542009-08-03 15:30:11 +000045#include "FreeValueMessage.h"
46#include "HostChannel.h"
47#include "LoadJsniMessage.h"
48#include "InvokeMessage.h"
49#include "InvokeSpecialMessage.h"
50#include "QuitMessage.h"
51#include "ReturnMessage.h"
52#include "Value.h"
53#include "scoped_ptr/scoped_ptr.h"
54
55using namespace std;
56
57ByteOrder HostChannel::byteOrder;
58
59bool HostChannel::connectToHost(const char* host, unsigned port) {
jat@google.com134be542009-08-03 15:30:11 +000060 if (!port) {
61 port = 9997;
62 }
jat@google.com23181962009-09-03 22:22:56 +000063 Debug::log(Debug::Info)
64 << "Initiating GWT Development Mode connection to host " << host
65 << ", port " << port << Debug::flush;
jat@google.com134be542009-08-03 15:30:11 +000066 return sock.connect(host, port);
67}
68
jat@google.com5e86cbd2009-08-22 23:59:24 +000069bool HostChannel::init(SessionHandler* handler, int minProtoVers,
70 int maxProtoVers, const std::string& hostedHtmlVers) {
scottb@google.comb0dbdff2009-11-23 21:18:40 +000071 this->handler = handler;
jat@google.com23181962009-09-03 22:22:56 +000072 Debug::log(Debug::Debugging)
73 << " negotiating versions - we support protocol " << minProtoVers
74 << " through " << maxProtoVers << ", hostedHtmlVersion=" << hostedHtmlVers
jat@google.com5e86cbd2009-08-22 23:59:24 +000075 << Debug::flush;
76 // TODO(jat): support transport selection
77 CheckVersionsMessage::send(*this, minProtoVers, maxProtoVers, hostedHtmlVers);
78 flush();
79 char type;
80 if (!readByte(type)) {
81 handler->fatalError(*this, "Failed to receive message type");
82 Debug::log(Debug::Error) << "Failed to receive message type" << Debug::flush;
83 disconnectFromHost();
84 return false;
85 }
86 switch (type) {
87 case MESSAGE_TYPE_PROTOCOL_VERSION:
88 {
89 scoped_ptr<ProtocolVersionMessage> imsg(ProtocolVersionMessage
90 ::receive(*this));
91 if (!imsg.get()) {
92 Debug::log(Debug::Error) << "Failed to receive protocol version message"
93 << Debug::flush;
94 return false;
95 }
96 // TODO(jat): save selected protocol version when we support a range
97 break;
98 }
99 case MESSAGE_TYPE_FATAL_ERROR:
100 {
101 scoped_ptr<FatalErrorMessage> imsg(FatalErrorMessage::receive(*this));
102 if (!imsg.get()) {
103 Debug::log(Debug::Error) << "Failed to receive fatal error message"
104 << Debug::flush;
105 return false;
106 }
107 handler->fatalError(*this, imsg.get()->getError());
108 return false;
109 }
110 default:
111 return false;
112 }
113 return true;
114}
115
jat@google.com134be542009-08-03 15:30:11 +0000116bool HostChannel::disconnectFromHost() {
117 Debug::log(Debug::Debugging) << "Disconnecting channel" << Debug::flush;
118 if (!isConnected()) {
119 Debug::log(Debug::Error) << "Disconnecting already disconnected channel" << Debug::flush;
120 return false;
121 }
122 QuitMessage::send(*this);
123 flush();
124 sock.disconnect();
125 return true;
126}
127
128bool HostChannel::readInt(int32_t& data) {
129 int32_t d;
130 if (!readBytes(&d, sizeof(d))) return false;
131 data = ntohl(d);
132 return true;
133}
134
135bool HostChannel::sendInt(int32_t data) {
136 uint32_t d = htonl(data);
137 return sendBytes(&d, sizeof(d));
138}
139
140bool HostChannel::readShort(short& data) {
141 int16_t d;
142 if (!readBytes(&d, sizeof(d))) return false;
143 data = ntohs(d);
144 return true;
145}
146
147bool HostChannel::sendShort(const short data) {
148 uint16_t d = htons(data);
149 return sendBytes(&d, sizeof(d));
150}
151
152bool HostChannel::readLong(int64_t& data) {
153 // network is big-endian
154 int32_t d[2];
155 if (!readInt(d[0])) return false;
156 if (!readInt(d[1])) return false;
157 data = (static_cast<int64_t>(d[0]) << 32) | ntohl(d[1]);
158 return true;
159}
160
161bool HostChannel::sendLong(const int64_t data) {
162 if (!sendInt(static_cast<int32_t>(data >> 32))) {
163 return false;
164 }
165 return sendInt(static_cast<int32_t>(data));
166}
167
168bool HostChannel::readFloat(float& data) {
169 char bytes[sizeof(data)];
170 if (!readBytes(bytes, sizeof(bytes))) {
171 return false;
172 }
173 data = byteOrder.floatFromBytes(bytes);
174 return true;
175}
176
177bool HostChannel::sendFloat(const float data) {
178 char bytes[sizeof(data)];
179 byteOrder.bytesFromFloat(data, bytes);
180 return sendBytes(bytes, sizeof(bytes));
181}
182
183bool HostChannel::readDouble(double& data) {
184 char bytes[sizeof(data)];
185 if (!readBytes(bytes, sizeof(bytes))) {
186 return false;
187 }
188 data = byteOrder.doubleFromBytes(bytes);
189 return true;
190}
191
192bool HostChannel::sendDouble(const double data) {
193 char bytes[sizeof(data)];
194 byteOrder.bytesFromDouble(data, bytes);
195 return sendBytes(bytes, sizeof(bytes));
196}
197
198bool HostChannel::readStringLength(uint32_t& data) {
199 int32_t val;
200 if (!readInt(val)) return false;
201 // TODO: assert positive?
202 data = val;
203 return true;
204}
205
206bool HostChannel::readStringBytes(char* data, const uint32_t len) {
207 return readBytes(data, len);
208}
209
210bool HostChannel::readString(std::string& strRef) {
211 uint32_t len;
212 if (!readStringLength(len)) {
213 Debug::log(Debug::Error) << "readString: failed to read length"
214 << Debug::flush;
215 return false;
216 }
217 // Allocating variable-length arrays on the stack is a GCC feature,
218 // and is vulnerable to stack overflow attacks, so we allocate on the heap.
219 scoped_array<char> buf(new char[len]);
220 if (!readStringBytes(buf.get(), len)) {
221 Debug::log(Debug::Error) << "readString: failed to read " << len
222 << " bytes" << Debug::flush;
223 return false;
224 }
225 strRef.assign(buf.get(), len);
226 return true;
227}
228
229static inline double operator-(const struct timeval& end,
230 const struct timeval& begin) {
231 double us = end.tv_sec * 1000000.0 + end.tv_usec - begin.tv_sec * 1000000.0
232 - begin.tv_usec;
233 return us;
234}
235
236ReturnMessage* HostChannel::reactToMessages(SessionHandler* handler, bool expectReturn) {
237 char type;
238 while (true) {
239 flush();
jat@google.com5e86cbd2009-08-22 23:59:24 +0000240 Debug::log(Debug::Spam) << "Waiting for response, flushed output"
241 << Debug::flush;
jat@google.com134be542009-08-03 15:30:11 +0000242 if (!readByte(type)) {
jat@google.com5e86cbd2009-08-22 23:59:24 +0000243 if (isConnected()) {
244 Debug::log(Debug::Error) << "Failed to receive message type"
245 << Debug::flush;
246 }
jat@google.com134be542009-08-03 15:30:11 +0000247 return 0;
248 }
249 switch (type) {
250 case MESSAGE_TYPE_INVOKE:
251 {
252 scoped_ptr<InvokeMessage> imsg(InvokeMessage::receive(*this));
253 if (!imsg.get()) {
254 Debug::log(Debug::Error) << "Failed to receive invoke message" << Debug::flush;
255 return 0;
256 }
257 Value returnValue;
258 bool exception = handler->invoke(*this, imsg->getThis(), imsg->getMethodName(),
259 imsg->getNumArgs(), imsg->getArgs(), &returnValue);
260 handler->sendFreeValues(*this);
261 ReturnMessage::send(*this, exception, returnValue);
262 }
263 break;
264 case MESSAGE_TYPE_INVOKESPECIAL:
265 {
266 // scottb: I think this is never used; I think server never sends invokeSpecial
267 scoped_ptr<InvokeSpecialMessage> imsg(InvokeSpecialMessage::receive(*this));
268 if (!imsg.get()) {
269 Debug::log(Debug::Error) << "Failed to receive invoke special message" << Debug::flush;
270 return 0;
271 }
272 Value returnValue;
273 bool exception = handler->invokeSpecial(*this, imsg->getDispatchId(),
274 imsg->getNumArgs(), imsg->getArgs(), &returnValue);
275 handler->sendFreeValues(*this);
276 ReturnMessage::send(*this, exception, returnValue);
277 }
278 break;
279 case MESSAGE_TYPE_FREEVALUE:
280 {
281 scoped_ptr<FreeValueMessage> freeMsg(FreeValueMessage::receive(*this));
282 if (!freeMsg.get()) {
283 Debug::log(Debug::Error) << "Failed to receive free value message" << Debug::flush;
284 return 0;
285 }
286 handler->freeValue(*this, freeMsg->getIdCount(), freeMsg->getIds());
287 }
288 // do not send a response
289 break;
290 case MESSAGE_TYPE_LOADJSNI:
291 {
292 scoped_ptr<LoadJsniMessage> loadMsg(LoadJsniMessage::receive(*this));
293 if (!loadMsg.get()) {
294 Debug::log(Debug::Error) << "Failed to receive load JSNI message" << Debug::flush;
295 return 0;
296 }
297 handler->loadJsni(*this, loadMsg->getJs());
298 }
299 // do not send a response
300 break;
301 case MESSAGE_TYPE_RETURN:
302 if (!expectReturn) {
303 Debug::log(Debug::Error) << "Received unexpected RETURN" << Debug::flush;
304 }
305 return ReturnMessage::receive(*this);
306 case MESSAGE_TYPE_QUIT:
307 if (expectReturn) {
308 Debug::log(Debug::Error) << "Received QUIT while waiting for return" << Debug::flush;
309 }
310 disconnectFromHost();
311 return 0;
312 default:
313 // TODO(jat): error handling
314 Debug::log(Debug::Error) << "Unexpected message type " << type
315 << ", expectReturn=" << expectReturn << Debug::flush;
316 disconnectFromHost();
317 return 0;
318 }
319 }
320}
321
322bool HostChannel::readValue(Value& valueRef) {
323 char typeBuf;
324 if (!readByte(typeBuf)) return false;
325 Value::ValueType type = Value::ValueType(typeBuf);
326 switch (type) {
327 case Value::NULL_TYPE:
328 valueRef.setNull();
329 return true;
330 case Value::UNDEFINED:
331 valueRef.setUndefined();
332 return true;
333 case Value::BOOLEAN:
334 {
335 char val;
336 if (!readByte(val)) return false;
337 valueRef.setBoolean(val != 0);
338 }
339 return true;
340 case Value::BYTE:
341 {
342 char val;
343 if (!readByte(val)) return false;
344 valueRef.setByte(val);
345 }
346 return true;
347 case Value::CHAR:
348 {
349 short val;
350 if (!readShort(val)) return false;
351 valueRef.setChar(val);
352 }
353 return true;
354 case Value::SHORT:
355 {
356 short val;
357 if (!readShort(val)) return false;
358 valueRef.setShort(val);
359 }
360 return true;
361 case Value::STRING:
362 {
363 std::string val;
364 if (!readString(val)) return false;
365 valueRef.setString(val);
366 }
367 return true;
368 case Value::INT:
369 {
370 int val;
371 if (!readInt(val)) return false;
372 valueRef.setInt(val);
373 }
374 return true;
375 case Value::LONG:
376 {
377 int64_t val;
378 if (!readLong(val)) return false;
379 valueRef.setLong(val);
380 }
381 return true;
382 case Value::DOUBLE:
383 {
384 double val;
385 if (!readDouble(val)) return false;
386 valueRef.setDouble(val);
387 }
388 return true;
389 case Value::JAVA_OBJECT:
390 {
391 int objId;
392 if (!readInt(objId)) return false;
393 valueRef.setJavaObject(objId);
394 }
395 return true;
396 case Value::JS_OBJECT:
397 {
398 int val;
399 if (!readInt(val)) return false;
400 valueRef.setJsObjectId(val);
401 }
402 return true;
403 default:
404 Debug::log(Debug::Error) << "Unhandled value type sent from server: " << type << Debug::flush;
405 break;
406 }
407 return false;
408}
409
410bool HostChannel::sendValue(const Value& value) {
411 Value::ValueType type = value.getType();
412 if (!sendByte(type)) return false;
413 switch (type) {
414 case Value::NULL_TYPE:
415 case Value::UNDEFINED:
416 // Null and Undefined only have the tag byte, no data
417 return true;
418 case Value::BOOLEAN:
419 return sendByte(value.getBoolean() ? 1 : 0);
420 case Value::BYTE:
421 return sendByte(value.getByte());
422 case Value::CHAR:
423 return sendShort(short(value.getChar()));
424 case Value::SHORT:
425 return sendShort(value.getShort());
426 case Value::INT:
427 return sendInt(value.getInt());
428 case Value::LONG:
429 return sendLong(value.getLong());
430 case Value::STRING:
431 return sendString(value.getString());
432 case Value::DOUBLE:
433 return sendDouble(value.getDouble());
434 case Value::FLOAT:
435 return sendFloat(value.getFloat());
436 case Value::JS_OBJECT:
437 return sendInt(value.getJsObjectId());
438 case Value::JAVA_OBJECT:
439 return sendInt(value.getJavaObjectId());
440 default:
441 Debug::log(Debug::Error) << "Unhandled value type sent to server: " << type << Debug::flush;
442 break;
443 }
444 return false;
445}