• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.google.polo.wire.protobuf;
18 
19 import com.google.polo.exception.BadSecretException;
20 import com.google.polo.exception.NoConfigurationException;
21 import com.google.polo.exception.PoloException;
22 import com.google.polo.exception.ProtocolErrorException;
23 import com.google.polo.pairing.PairingContext;
24 import com.google.polo.pairing.PoloUtil;
25 import com.google.polo.pairing.message.ConfigurationAckMessage;
26 import com.google.polo.pairing.message.ConfigurationMessage;
27 import com.google.polo.pairing.message.EncodingOption;
28 import com.google.polo.pairing.message.OptionsMessage;
29 import com.google.polo.pairing.message.PairingRequestAckMessage;
30 import com.google.polo.pairing.message.PairingRequestMessage;
31 import com.google.polo.pairing.message.PoloMessage;
32 import com.google.polo.pairing.message.SecretAckMessage;
33 import com.google.polo.pairing.message.SecretMessage;
34 import com.google.polo.wire.PoloWireInterface;
35 import com.google.polo.wire.protobuf.nano.PoloProto;
36 import com.google.polo.wire.protobuf.nano.PoloProto.OuterMessage;
37 import com.google.protobuf.nano.MessageNano;
38 
39 import java.io.IOException;
40 import java.io.InputStream;
41 import 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  */
57 public 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      */
ProtobufWireAdapter(InputStream input, OutputStream output)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      */
fromContext(PairingContext context)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      */
getNextMessage()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      */
getNextMessage(PoloMessage.PoloMessageType type)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      */
readNextOuterMessage()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      */
readNextInnerMessage()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      */
readBytesBlocking(int numBytes)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      */
wrapInnerMessage(MessageNano message)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      */
writeMessage(OuterMessage message)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      */
sendMessage(PoloMessage message)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      */
sendErrorMessage(Exception e)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      */
poloMessageToProto(PoloMessage poloMessage)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      */
toProto(PairingRequestMessage poloMessage)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      */
toProto(PairingRequestAckMessage poloMessage)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      */
toProto(OptionsMessage poloMessage)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      */
toProto(ConfigurationMessage poloMessage)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      */
toProto(EncodingOption enc)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      */
toProto(OptionsMessage.ProtocolRole role)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      */
toProto(ConfigurationAckMessage poloMessage)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      */
toProto(SecretMessage poloMessage)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      */
toProto(SecretAckMessage poloMessage)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      */
protoToPoloMessage(MessageNano protoMessage)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      */
fromProto(PoloProto.PairingRequest protoMessage)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      */
fromProto(PoloProto.PairingRequestAck protoMessage)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      */
fromProto(PoloProto.Options protoMessage)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      */
fromProto(PoloProto.Configuration protoMessage)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      */
fromProto(PoloProto.ConfigurationAck protoMessage)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      */
fromProto(PoloProto.Secret protoMessage)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      */
fromProto(PoloProto.SecretAck protoMessage)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      */
fromProto(PoloProto.Options.Encoding enc)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 }
581