blob: ea3a7cbed674907f12b5b0f3e2f12882414e25a5 [file] [log] [blame]
Jerome Poichet7c997852014-05-20 10:50:05 -07001/*
2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.polo.wire.protobuf;
18
19import com.google.polo.exception.BadSecretException;
20import com.google.polo.exception.NoConfigurationException;
21import com.google.polo.exception.PoloException;
22import com.google.polo.exception.ProtocolErrorException;
23import com.google.polo.pairing.PairingContext;
24import com.google.polo.pairing.PoloUtil;
25import com.google.polo.pairing.message.ConfigurationAckMessage;
26import com.google.polo.pairing.message.ConfigurationMessage;
27import com.google.polo.pairing.message.EncodingOption;
28import com.google.polo.pairing.message.OptionsMessage;
29import com.google.polo.pairing.message.PairingRequestAckMessage;
30import com.google.polo.pairing.message.PairingRequestMessage;
31import com.google.polo.pairing.message.PoloMessage;
32import com.google.polo.pairing.message.SecretAckMessage;
33import com.google.polo.pairing.message.SecretMessage;
34import com.google.polo.wire.PoloWireInterface;
Tamas Berghammere69f0862017-01-18 16:19:39 +000035import com.google.polo.wire.protobuf.PoloProto.OuterMessage;
Jerome Poichet7c997852014-05-20 10:50:05 -070036import com.google.protobuf.nano.MessageNano;
37
38import java.io.IOException;
39import java.io.InputStream;
40import java.io.OutputStream;
41
42/**
43 * Implementation of {@link PoloWireInterface} that uses Protocol Buffers for
44 * the data representation.
45 * <p/>
46 * The primary work of this class is to translate Protocol Buffer messages
47 * instances (derived from {@link MessageNano} to an internal message
48 * instance (derived from {@link PoloMessage}, and vice versa.
49 * <p/>
50 * The reason we are going through all this trouble, and not using protocol
51 * buffer objects directly, is that we'd like to limit the scope of protocol
52 * buffers to the wire protocol only. Some applications may prefer to use
53 * a different wire format, where the requirement of adding the protobuf library
54 * could be an impediment.
55 */
56public class ProtobufWireAdapter implements PoloWireInterface {
57
58 /**
59 * The output coming from the peer.
60 */
61 private final InputStream mInputStream;
62 /**
63 * The input going to the peer.
64 */
65 private final OutputStream mOutputStream;
66
67 /**
68 * Constructor.
69 *
70 * @param input the {@link InputStream} from the peer
71 * @param output the {@link OutputStream} to the peer
72 */
73 public ProtobufWireAdapter(InputStream input, OutputStream output) {
74 mInputStream = input;
75 mOutputStream = output;
76 }
77
78 /**
79 * Generates a new instance from a {@link PairingContext}.
80 *
81 * @param context the {@link PairingContext}
82 * @return the new instance
83 */
84 public static ProtobufWireAdapter fromContext(PairingContext context) {
85 return new ProtobufWireAdapter(context.getPeerInputStream(),
86 context.getPeerOutputStream());
87 }
88
89 /**
90 * Returns the next message sent over the wire, blocking as necessary.
91 */
92 public PoloMessage getNextMessage() throws IOException, PoloException {
93 return protoToPoloMessage(readNextInnerMessage());
94 }
95
96 /**
97 * Returns the next message read over the wire, requiring it to be a certain
98 * type.
99 *
100 * @param type the required message type
101 * @throws IOException on error during read
102 * @throws PoloException if the wrong message type was read, or on protocol
103 * error
104 */
105 public PoloMessage getNextMessage(PoloMessage.PoloMessageType type)
106 throws IOException, PoloException {
107 PoloMessage message = getNextMessage();
108 if (message.getType() != type) {
109 throw new PoloException("Wrong message type (wanted " + type +
110 ", got " + message.getType() + ")");
111 }
112 return message;
113 }
114
115 /**
116 * Returns the next message seen on the input stream.
117 *
118 * @return the next OuterMessage read from the wire
119 * @throws IOException on error during read
120 */
121 private OuterMessage readNextOuterMessage() throws IOException, PoloException {
122 // Read the preamble (length of payload)
123 byte[] preambleBuffer = readBytesBlocking(4);
124 int messageLen = (int) PoloUtil.intBigEndianBytesToLong(preambleBuffer);
125
126 // Read the payload (serialized PoloMessage)
127 byte[] messageBuffer = readBytesBlocking(messageLen);
128
129 // Decode and return the payload
130 OuterMessage message = OuterMessage.parseFrom(messageBuffer);
131
132 if (message.status != OuterMessage.STATUS_OK) {
133 throw new ProtocolErrorException();
134 }
135
136 return message;
137 }
138
139 /**
140 * Reads the next inner message from the wire, decoding and handling the outer
141 * message in the process.
142 *
143 * @return a protocol buffer message
144 * @throws IOException on error during read
145 * @throws PoloException on protocol error
146 */
147 private MessageNano readNextInnerMessage()
148 throws IOException, PoloException {
149 OuterMessage message = readNextOuterMessage();
150
151 byte[] payload = message.payload;
152
153 if (message.type == OuterMessage.MESSAGE_TYPE_OPTIONS) {
154 return PoloProto.Options.parseFrom(payload);
155 } else if (message.type == OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST) {
156 return PoloProto.PairingRequest.parseFrom(payload);
157 } else if (message.type == OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST_ACK) {
158 return PoloProto.PairingRequestAck.parseFrom(payload);
159 } else if (message.type == OuterMessage.MESSAGE_TYPE_CONFIGURATION) {
160 return PoloProto.Configuration.parseFrom(payload);
161 } else if (message.type == OuterMessage.MESSAGE_TYPE_CONFIGURATION_ACK) {
162 return PoloProto.ConfigurationAck.parseFrom(payload);
163 } else if (message.type == OuterMessage.MESSAGE_TYPE_SECRET) {
164 return PoloProto.Secret.parseFrom(payload);
165 } else if (message.type == OuterMessage.MESSAGE_TYPE_SECRET_ACK) {
166 return PoloProto.SecretAck.parseFrom(payload);
167 }
168
169 throw new IOException("Could not unparse message");
170 }
171
172 /**
173 * Convenience method to read a fixed number of bytes from the client
174 * InputStream, blocking if necessary.
175 *
176 * @param numBytes the number of bytes to read
177 * @return the bytes read
178 * @throws IOException on error during read
179 */
180 private byte[] readBytesBlocking(int numBytes) throws IOException {
181 byte[] buf = new byte[numBytes];
182 int bytesRead = 0;
183
184 // For an SSLSocket, read() can frequently return zero bytes,
185 // or fewer bytes than desired, due to SSL unwrapping and other
186 // non-application-data events.
187 while (bytesRead < numBytes) {
188 int inc = mInputStream.read(buf, bytesRead, numBytes - bytesRead);
189 if (inc < 0) {
190 throw new IOException("Stream closed while reading.");
191 }
192 bytesRead += inc;
193 }
194 return buf;
195 }
196
197 /**
198 * Wraps an outer message in an inner message.
199 *
200 * @param message the {@link MessageNano} to wrap
201 * @throws PoloException if the message was not well formed
202 */
203 private OuterMessage wrapInnerMessage(MessageNano message)
204 throws PoloException {
205 int type;
206 if (message instanceof PoloProto.Options) {
207 type = OuterMessage.MESSAGE_TYPE_OPTIONS;
208 } else if (message instanceof PoloProto.PairingRequest) {
209 type = OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST;
210 } else if (message instanceof PoloProto.PairingRequestAck) {
211 type = OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST_ACK;
212 } else if (message instanceof PoloProto.Configuration) {
213 type = OuterMessage.MESSAGE_TYPE_CONFIGURATION;
214 } else if (message instanceof PoloProto.ConfigurationAck) {
215 type = OuterMessage.MESSAGE_TYPE_CONFIGURATION_ACK;
216 } else if (message instanceof PoloProto.Secret) {
217 type = OuterMessage.MESSAGE_TYPE_SECRET;
218 } else if (message instanceof PoloProto.SecretAck) {
219 type = OuterMessage.MESSAGE_TYPE_SECRET_ACK;
220 } else {
221 throw new PoloException("Bad inner message type.");
222 }
223
224 // compose outer message
225 OuterMessage outerMessage = new OuterMessage();
226 outerMessage.status = OuterMessage.STATUS_OK;
227 outerMessage.protocolVersion = 1;
228 outerMessage.type = type;
229 outerMessage.payload = MessageNano.toByteArray(message);
230 return outerMessage;
231 }
232
233 /**
234 * Writes an {@link OuterMessage} to the wire.
235 *
236 * @param message the message
237 * @throws IOException on error during write
238 */
239 private void writeMessage(OuterMessage message) throws IOException {
240 byte[] messageBytes = message.payload;
241 int messageLength = messageBytes.length;
242
243 mOutputStream.write(PoloUtil.intToBigEndianIntBytes(messageLength));
244 mOutputStream.write(messageBytes);
245 }
246
247 /**
248 * Writes a new message to the wire.
249 */
250 public void sendMessage(PoloMessage message)
251 throws IOException, PoloException {
252 MessageNano pb = poloMessageToProto(message);
253 OuterMessage outerMessage = wrapInnerMessage(pb);
254 writeMessage(outerMessage);
255 }
256
257 /**
258 * Sends a new error message to the wire.
259 */
260 public void sendErrorMessage(Exception e) throws IOException {
261 OuterMessage outerMessage = new OuterMessage();
262 outerMessage.protocolVersion = 1;
263
264 if (e instanceof NoConfigurationException) {
265 outerMessage.status = OuterMessage.STATUS_BAD_CONFIGURATION;
266 } else if (e instanceof BadSecretException) {
267 outerMessage.status = OuterMessage.STATUS_BAD_SECRET;
268 } else {
269 outerMessage.status = OuterMessage.STATUS_ERROR;
270 }
271
272 writeMessage(outerMessage);
273 }
274
275 /**
276 * Converts an internal message to the corresponding protocol buffer message.
277 *
278 * @param poloMessage the internal message
279 * @return a new {@link MessageNano} instance
280 */
281 private MessageNano poloMessageToProto(PoloMessage poloMessage) {
282 if (poloMessage instanceof PairingRequestMessage) {
283 return toProto((PairingRequestMessage) poloMessage);
284 } else if (poloMessage instanceof PairingRequestAckMessage) {
285 return toProto((PairingRequestAckMessage) poloMessage);
286 } else if (poloMessage instanceof OptionsMessage) {
287 return toProto((OptionsMessage) poloMessage);
288 } else if (poloMessage instanceof ConfigurationMessage) {
289 return toProto((ConfigurationMessage) poloMessage);
290 } else if (poloMessage instanceof ConfigurationAckMessage) {
291 return toProto((ConfigurationAckMessage) poloMessage);
292 } else if (poloMessage instanceof SecretMessage) {
293 return toProto((SecretMessage) poloMessage);
294 } else if (poloMessage instanceof SecretAckMessage) {
295 return toProto((SecretAckMessage) poloMessage);
296 }
297 return null;
298 }
299
300 /**
301 * Converts a {@link PairingRequestMessage} to a
302 * {@link PoloProto.PairingRequest}.
303 */
304 private PoloProto.PairingRequest toProto(PairingRequestMessage poloMessage) {
305 PoloProto.PairingRequest pairingRequest = new PoloProto.PairingRequest();
306 pairingRequest.serviceName = poloMessage.getServiceName();
307
308 if (poloMessage.hasClientName()) {
309 pairingRequest.clientName = poloMessage.getClientName();
310 }
311 return pairingRequest;
312 }
313
314 /**
315 * Converts a {@link PairingRequestAckMessage} to a
316 * {@link PoloProto.PairingRequestAck}.
317 */
318 private PoloProto.PairingRequestAck toProto(PairingRequestAckMessage poloMessage) {
319 PoloProto.PairingRequestAck pairingRequestAck = new PoloProto.PairingRequestAck();
320 if (poloMessage.hasServerName()) {
321 pairingRequestAck.serverName = poloMessage.getServerName();
322 }
323 return pairingRequestAck;
324 }
325
326 /**
327 * Converts a {@link OptionsMessage} to a {@link PoloProto.Options}.
328 */
329 private PoloProto.Options toProto(OptionsMessage poloMessage) {
330 PoloProto.Options options = new PoloProto.Options();
331
332 switch (poloMessage.getProtocolRolePreference()) {
333 case DISPLAY_DEVICE:
334 options.preferredRole = PoloProto.Options.ROLE_TYPE_INPUT;
335 break;
336 case INPUT_DEVICE:
337 options.preferredRole = PoloProto.Options.ROLE_TYPE_OUTPUT;
338 break;
339 }
340
341 int i = 0, n = poloMessage.getOutputEncodingSet().size();
342 options.outputEncodings = new PoloProto.Options.Encoding[n];
343 for (EncodingOption enc : poloMessage.getOutputEncodingSet()) {
344 options.outputEncodings[i++] = toProto(enc);
345 }
346
347 i = 0;
348 n = poloMessage.getInputEncodingSet().size();
349 options.inputEncodings = new PoloProto.Options.Encoding[n];
350 for (EncodingOption enc : poloMessage.getInputEncodingSet()) {
351 options.inputEncodings[i++] = toProto(enc);
352 }
353
354 return options;
355 }
356
357 /**
358 * Converts a {@link ConfigurationMessage} to a
359 * {@link PoloProto.Configuration}.
360 */
361 private PoloProto.Configuration toProto(ConfigurationMessage poloMessage) {
362 PoloProto.Configuration configuration = new PoloProto.Configuration();
363 configuration.encoding = toProto(poloMessage.getEncoding());
364 configuration.clientRole = toProto(poloMessage.getClientRole());
365 return configuration;
366 }
367
368 /**
369 * Converts a {@link EncodingOption} to a {@link PoloProto.Options.Encoding}.
370 */
371 private PoloProto.Options.Encoding toProto(EncodingOption enc) {
372 PoloProto.Options.Encoding encoding = new PoloProto.Options.Encoding();
373
374 switch (enc.getType()) {
375 case ENCODING_ALPHANUMERIC:
376 encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_ALPHANUMERIC;
377 break;
378 case ENCODING_HEXADECIMAL:
379 encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_HEXADECIMAL;
380 break;
381 case ENCODING_NUMERIC:
382 encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_NUMERIC;
383 break;
384 case ENCODING_QRCODE:
385 encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_QRCODE;
386 break;
387 default:
388 encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_UNKNOWN;
389 break;
390 }
391
392 encoding.symbolLength = enc.getSymbolLength();
393 return encoding;
394 }
395
396 /**
397 * Converts a {@link OptionsMessage.ProtocolRole} to a
398 * {@link PoloProto.Options}.
399 */
400 private int toProto(OptionsMessage.ProtocolRole role) {
401 switch (role) {
402 case DISPLAY_DEVICE:
403 return PoloProto.Options.ROLE_TYPE_OUTPUT;
404 case INPUT_DEVICE:
405 return PoloProto.Options.ROLE_TYPE_INPUT;
406 default:
407 return PoloProto.Options.ROLE_TYPE_UNKNOWN;
408 }
409 }
410
411 /**
412 * Converts a {@link ConfigurationAckMessage} to a
413 * {@link PoloProto.ConfigurationAck}.
414 */
415 private PoloProto.ConfigurationAck toProto(ConfigurationAckMessage poloMessage) {
416 PoloProto.ConfigurationAck configurationAck = new PoloProto.ConfigurationAck();
417 return configurationAck;
418 }
419
420 /**
421 * Converts a {@link SecretMessage} to a {@link PoloProto.Secret}.
422 */
423 private PoloProto.Secret toProto(SecretMessage poloMessage) {
424 PoloProto.Secret secret = new PoloProto.Secret();
425 secret.secret = poloMessage.getSecret();
426 return secret;
427 }
428
429 /**
430 * Converts a {@link SecretAckMessage} to a {@link PoloProto.SecretAck}.
431 */
432 private PoloProto.SecretAck toProto(SecretAckMessage poloMessage) {
433 PoloProto.SecretAck secretAck = new PoloProto.SecretAck();
434 secretAck.secret = poloMessage.getSecret();
435 return secretAck;
436 }
437
438 //
439 // polo -> protocol buffer routines
440 //
441
442 /**
443 * Converts a protocol buffer message to the corresponding internal
444 * message.
445 *
446 * @param protoMessage the protobuf message to convert
447 * @return the new {@link PoloMessage}
448 */
449 private PoloMessage protoToPoloMessage(MessageNano protoMessage) {
450 if (protoMessage instanceof PoloProto.PairingRequest) {
451 return fromProto((PoloProto.PairingRequest) protoMessage);
452 } else if (protoMessage instanceof PoloProto.PairingRequestAck) {
453 return fromProto((PoloProto.PairingRequestAck) protoMessage);
454 } else if (protoMessage instanceof PoloProto.Options) {
455 return fromProto((PoloProto.Options) protoMessage);
456 } else if (protoMessage instanceof PoloProto.Configuration) {
457 return fromProto((PoloProto.Configuration) protoMessage);
458 } else if (protoMessage instanceof PoloProto.ConfigurationAck) {
459 return fromProto((PoloProto.ConfigurationAck) protoMessage);
460 } else if (protoMessage instanceof PoloProto.Secret) {
461 return fromProto((PoloProto.Secret) protoMessage);
462 } else if (protoMessage instanceof PoloProto.SecretAck) {
463 return fromProto((PoloProto.SecretAck) protoMessage);
464 }
465 return null;
466 }
467
468 /**
469 * Converts a {@link PoloProto.PairingRequest} to a
470 * {@link PairingRequestMessage}.
471 */
472 private PairingRequestMessage fromProto(PoloProto.PairingRequest protoMessage) {
473 return new PairingRequestMessage(protoMessage.serviceName, protoMessage.clientName);
474 }
475
476 /**
477 * Converts a {@link PoloProto.PairingRequestAck} to a
478 * {@link PairingRequestAckMessage}.
479 */
480 private PairingRequestAckMessage fromProto(PoloProto.PairingRequestAck protoMessage) {
481 return new PairingRequestAckMessage(protoMessage.serverName);
482 }
483
484 /**
485 * Converts a {@link PoloProto.Options} to a {@link OptionsMessage}.
486 */
487 private OptionsMessage fromProto(PoloProto.Options protoMessage) {
488 OptionsMessage optionsMessage = new OptionsMessage();
489
490 switch (protoMessage.preferredRole) {
491 case PoloProto.Options.ROLE_TYPE_INPUT:
492 optionsMessage.setProtocolRolePreference(OptionsMessage.ProtocolRole.INPUT_DEVICE);
493 break;
494 case PoloProto.Options.ROLE_TYPE_OUTPUT:
495 optionsMessage.setProtocolRolePreference(OptionsMessage.ProtocolRole.DISPLAY_DEVICE);
496 break;
497 }
498
499 for (PoloProto.Options.Encoding e : protoMessage.inputEncodings) {
500 optionsMessage.addInputEncoding(fromProto(e));
501 }
502
503 for (PoloProto.Options.Encoding e : protoMessage.outputEncodings) {
504 optionsMessage.addOutputEncoding(fromProto(e));
505 }
506
507 return optionsMessage;
508 }
509
510 /**
511 * Converts a {@link PoloProto.Configuration} to a
512 * {@link ConfigurationMessage}.
513 */
514 private ConfigurationMessage fromProto(PoloProto.Configuration protoMessage) {
515 EncodingOption enc = fromProto(protoMessage.encoding);
516 OptionsMessage.ProtocolRole role = OptionsMessage.ProtocolRole.UNKNOWN;
517
518 switch (protoMessage.clientRole) {
519 case PoloProto.Options.ROLE_TYPE_INPUT:
520 role = OptionsMessage.ProtocolRole.INPUT_DEVICE;
521 break;
522 case PoloProto.Options.ROLE_TYPE_OUTPUT:
523 role = OptionsMessage.ProtocolRole.DISPLAY_DEVICE;
524 break;
525 }
526
527 return new ConfigurationMessage(enc, role);
528 }
529
530 /**
531 * Converts a {@link PoloProto.ConfigurationAck} to a
532 * {@link ConfigurationAckMessage}.
533 */
534 private ConfigurationAckMessage fromProto(PoloProto.ConfigurationAck protoMessage) {
535 return new ConfigurationAckMessage();
536 }
537
538 /**
539 * Converts a {@link PoloProto.Secret} to a {@link SecretMessage}.
540 */
541 private SecretMessage fromProto(PoloProto.Secret protoMessage) {
542 return new SecretMessage(protoMessage.secret);
543 }
544
545 /**
546 * Converts a {@link PoloProto.SecretAck} to a {@link SecretAckMessage}.
547 */
548 private SecretAckMessage fromProto(PoloProto.SecretAck protoMessage) {
549 return new SecretAckMessage(protoMessage.secret);
550 }
551
552 /**
553 * Converts a {@link PoloProto.Options.Encoding} to a {@link EncodingOption}.
554 */
555 private EncodingOption fromProto(PoloProto.Options.Encoding enc) {
556 EncodingOption.EncodingType type;
557
558 switch (enc.type) {
559 case PoloProto.Options.Encoding.ENCODING_TYPE_ALPHANUMERIC:
560 type = EncodingOption.EncodingType.ENCODING_ALPHANUMERIC;
561 break;
562 case PoloProto.Options.Encoding.ENCODING_TYPE_HEXADECIMAL:
563 type = EncodingOption.EncodingType.ENCODING_HEXADECIMAL;
564 break;
565 case PoloProto.Options.Encoding.ENCODING_TYPE_NUMERIC:
566 type = EncodingOption.EncodingType.ENCODING_NUMERIC;
567 break;
568 case PoloProto.Options.Encoding.ENCODING_TYPE_QRCODE:
569 type = EncodingOption.EncodingType.ENCODING_QRCODE;
570 break;
571 default:
572 type = EncodingOption.EncodingType.ENCODING_UNKNOWN;
573 }
574
575 return new EncodingOption(type, enc.symbolLength);
576
577 }
578
579}