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