blob: 896667e4a5a76d3e0542a3b270682c6122cc6753 [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
40#include "FreeValueMessage.h"
41#include "HostChannel.h"
42#include "LoadJsniMessage.h"
43#include "InvokeMessage.h"
44#include "InvokeSpecialMessage.h"
45#include "QuitMessage.h"
46#include "ReturnMessage.h"
47#include "Value.h"
48#include "scoped_ptr/scoped_ptr.h"
49
50using namespace std;
51
52ByteOrder HostChannel::byteOrder;
53
54bool HostChannel::connectToHost(const char* host, unsigned port) {
55 Debug::log(Debug::Info) << "Initiating GWT hosted mode connection to host "
56 << host << ", port " << port << Debug::flush;
57 if (!port) {
58 port = 9997;
59 }
60 if (!whitelist.isAllowed(host, port)) {
61 Debug::log(Debug::Error) << "Permission to connect to " << host << ":" << port
62 << " denied" << Debug::flush;
63 return false;
64 }
65 return sock.connect(host, port);
66}
67
68bool HostChannel::disconnectFromHost() {
69 Debug::log(Debug::Debugging) << "Disconnecting channel" << Debug::flush;
70 if (!isConnected()) {
71 Debug::log(Debug::Error) << "Disconnecting already disconnected channel" << Debug::flush;
72 return false;
73 }
74 QuitMessage::send(*this);
75 flush();
76 sock.disconnect();
77 return true;
78}
79
80bool HostChannel::readInt(int32_t& data) {
81 int32_t d;
82 if (!readBytes(&d, sizeof(d))) return false;
83 data = ntohl(d);
84 return true;
85}
86
87bool HostChannel::sendInt(int32_t data) {
88 uint32_t d = htonl(data);
89 return sendBytes(&d, sizeof(d));
90}
91
92bool HostChannel::readShort(short& data) {
93 int16_t d;
94 if (!readBytes(&d, sizeof(d))) return false;
95 data = ntohs(d);
96 return true;
97}
98
99bool HostChannel::sendShort(const short data) {
100 uint16_t d = htons(data);
101 return sendBytes(&d, sizeof(d));
102}
103
104bool HostChannel::readLong(int64_t& data) {
105 // network is big-endian
106 int32_t d[2];
107 if (!readInt(d[0])) return false;
108 if (!readInt(d[1])) return false;
109 data = (static_cast<int64_t>(d[0]) << 32) | ntohl(d[1]);
110 return true;
111}
112
113bool HostChannel::sendLong(const int64_t data) {
114 if (!sendInt(static_cast<int32_t>(data >> 32))) {
115 return false;
116 }
117 return sendInt(static_cast<int32_t>(data));
118}
119
120bool HostChannel::readFloat(float& data) {
121 char bytes[sizeof(data)];
122 if (!readBytes(bytes, sizeof(bytes))) {
123 return false;
124 }
125 data = byteOrder.floatFromBytes(bytes);
126 return true;
127}
128
129bool HostChannel::sendFloat(const float data) {
130 char bytes[sizeof(data)];
131 byteOrder.bytesFromFloat(data, bytes);
132 return sendBytes(bytes, sizeof(bytes));
133}
134
135bool HostChannel::readDouble(double& data) {
136 char bytes[sizeof(data)];
137 if (!readBytes(bytes, sizeof(bytes))) {
138 return false;
139 }
140 data = byteOrder.doubleFromBytes(bytes);
141 return true;
142}
143
144bool HostChannel::sendDouble(const double data) {
145 char bytes[sizeof(data)];
146 byteOrder.bytesFromDouble(data, bytes);
147 return sendBytes(bytes, sizeof(bytes));
148}
149
150bool HostChannel::readStringLength(uint32_t& data) {
151 int32_t val;
152 if (!readInt(val)) return false;
153 // TODO: assert positive?
154 data = val;
155 return true;
156}
157
158bool HostChannel::readStringBytes(char* data, const uint32_t len) {
159 return readBytes(data, len);
160}
161
162bool HostChannel::readString(std::string& strRef) {
163 uint32_t len;
164 if (!readStringLength(len)) {
165 Debug::log(Debug::Error) << "readString: failed to read length"
166 << Debug::flush;
167 return false;
168 }
169 // Allocating variable-length arrays on the stack is a GCC feature,
170 // and is vulnerable to stack overflow attacks, so we allocate on the heap.
171 scoped_array<char> buf(new char[len]);
172 if (!readStringBytes(buf.get(), len)) {
173 Debug::log(Debug::Error) << "readString: failed to read " << len
174 << " bytes" << Debug::flush;
175 return false;
176 }
177 strRef.assign(buf.get(), len);
178 return true;
179}
180
181static inline double operator-(const struct timeval& end,
182 const struct timeval& begin) {
183 double us = end.tv_sec * 1000000.0 + end.tv_usec - begin.tv_sec * 1000000.0
184 - begin.tv_usec;
185 return us;
186}
187
188ReturnMessage* HostChannel::reactToMessages(SessionHandler* handler, bool expectReturn) {
189 char type;
190 while (true) {
191 flush();
192 Debug::log(Debug::Spam) << "Waiting for response, flushed output" << Debug::flush;
193 if (!readByte(type)) {
194 Debug::log(Debug::Error) << "Failed to receive message type" << Debug::flush;
195 return 0;
196 }
197 switch (type) {
198 case MESSAGE_TYPE_INVOKE:
199 {
200 scoped_ptr<InvokeMessage> imsg(InvokeMessage::receive(*this));
201 if (!imsg.get()) {
202 Debug::log(Debug::Error) << "Failed to receive invoke message" << Debug::flush;
203 return 0;
204 }
205 Value returnValue;
206 bool exception = handler->invoke(*this, imsg->getThis(), imsg->getMethodName(),
207 imsg->getNumArgs(), imsg->getArgs(), &returnValue);
208 handler->sendFreeValues(*this);
209 ReturnMessage::send(*this, exception, returnValue);
210 }
211 break;
212 case MESSAGE_TYPE_INVOKESPECIAL:
213 {
214 // scottb: I think this is never used; I think server never sends invokeSpecial
215 scoped_ptr<InvokeSpecialMessage> imsg(InvokeSpecialMessage::receive(*this));
216 if (!imsg.get()) {
217 Debug::log(Debug::Error) << "Failed to receive invoke special message" << Debug::flush;
218 return 0;
219 }
220 Value returnValue;
221 bool exception = handler->invokeSpecial(*this, imsg->getDispatchId(),
222 imsg->getNumArgs(), imsg->getArgs(), &returnValue);
223 handler->sendFreeValues(*this);
224 ReturnMessage::send(*this, exception, returnValue);
225 }
226 break;
227 case MESSAGE_TYPE_FREEVALUE:
228 {
229 scoped_ptr<FreeValueMessage> freeMsg(FreeValueMessage::receive(*this));
230 if (!freeMsg.get()) {
231 Debug::log(Debug::Error) << "Failed to receive free value message" << Debug::flush;
232 return 0;
233 }
234 handler->freeValue(*this, freeMsg->getIdCount(), freeMsg->getIds());
235 }
236 // do not send a response
237 break;
238 case MESSAGE_TYPE_LOADJSNI:
239 {
240 scoped_ptr<LoadJsniMessage> loadMsg(LoadJsniMessage::receive(*this));
241 if (!loadMsg.get()) {
242 Debug::log(Debug::Error) << "Failed to receive load JSNI message" << Debug::flush;
243 return 0;
244 }
245 handler->loadJsni(*this, loadMsg->getJs());
246 }
247 // do not send a response
248 break;
249 case MESSAGE_TYPE_RETURN:
250 if (!expectReturn) {
251 Debug::log(Debug::Error) << "Received unexpected RETURN" << Debug::flush;
252 }
253 return ReturnMessage::receive(*this);
254 case MESSAGE_TYPE_QUIT:
255 if (expectReturn) {
256 Debug::log(Debug::Error) << "Received QUIT while waiting for return" << Debug::flush;
257 }
258 disconnectFromHost();
259 return 0;
260 default:
261 // TODO(jat): error handling
262 Debug::log(Debug::Error) << "Unexpected message type " << type
263 << ", expectReturn=" << expectReturn << Debug::flush;
264 disconnectFromHost();
265 return 0;
266 }
267 }
268}
269
270bool HostChannel::readValue(Value& valueRef) {
271 char typeBuf;
272 if (!readByte(typeBuf)) return false;
273 Value::ValueType type = Value::ValueType(typeBuf);
274 switch (type) {
275 case Value::NULL_TYPE:
276 valueRef.setNull();
277 return true;
278 case Value::UNDEFINED:
279 valueRef.setUndefined();
280 return true;
281 case Value::BOOLEAN:
282 {
283 char val;
284 if (!readByte(val)) return false;
285 valueRef.setBoolean(val != 0);
286 }
287 return true;
288 case Value::BYTE:
289 {
290 char val;
291 if (!readByte(val)) return false;
292 valueRef.setByte(val);
293 }
294 return true;
295 case Value::CHAR:
296 {
297 short val;
298 if (!readShort(val)) return false;
299 valueRef.setChar(val);
300 }
301 return true;
302 case Value::SHORT:
303 {
304 short val;
305 if (!readShort(val)) return false;
306 valueRef.setShort(val);
307 }
308 return true;
309 case Value::STRING:
310 {
311 std::string val;
312 if (!readString(val)) return false;
313 valueRef.setString(val);
314 }
315 return true;
316 case Value::INT:
317 {
318 int val;
319 if (!readInt(val)) return false;
320 valueRef.setInt(val);
321 }
322 return true;
323 case Value::LONG:
324 {
325 int64_t val;
326 if (!readLong(val)) return false;
327 valueRef.setLong(val);
328 }
329 return true;
330 case Value::DOUBLE:
331 {
332 double val;
333 if (!readDouble(val)) return false;
334 valueRef.setDouble(val);
335 }
336 return true;
337 case Value::JAVA_OBJECT:
338 {
339 int objId;
340 if (!readInt(objId)) return false;
341 valueRef.setJavaObject(objId);
342 }
343 return true;
344 case Value::JS_OBJECT:
345 {
346 int val;
347 if (!readInt(val)) return false;
348 valueRef.setJsObjectId(val);
349 }
350 return true;
351 default:
352 Debug::log(Debug::Error) << "Unhandled value type sent from server: " << type << Debug::flush;
353 break;
354 }
355 return false;
356}
357
358bool HostChannel::sendValue(const Value& value) {
359 Value::ValueType type = value.getType();
360 if (!sendByte(type)) return false;
361 switch (type) {
362 case Value::NULL_TYPE:
363 case Value::UNDEFINED:
364 // Null and Undefined only have the tag byte, no data
365 return true;
366 case Value::BOOLEAN:
367 return sendByte(value.getBoolean() ? 1 : 0);
368 case Value::BYTE:
369 return sendByte(value.getByte());
370 case Value::CHAR:
371 return sendShort(short(value.getChar()));
372 case Value::SHORT:
373 return sendShort(value.getShort());
374 case Value::INT:
375 return sendInt(value.getInt());
376 case Value::LONG:
377 return sendLong(value.getLong());
378 case Value::STRING:
379 return sendString(value.getString());
380 case Value::DOUBLE:
381 return sendDouble(value.getDouble());
382 case Value::FLOAT:
383 return sendFloat(value.getFloat());
384 case Value::JS_OBJECT:
385 return sendInt(value.getJsObjectId());
386 case Value::JAVA_OBJECT:
387 return sendInt(value.getJavaObjectId());
388 default:
389 Debug::log(Debug::Error) << "Unhandled value type sent to server: " << type << Debug::flush;
390 break;
391 }
392 return false;
393}