blob: f98c6bb8b3defac4eb0dc3f029d637056f726b9b [file] [log] [blame]
Nathan Bullockbdabded2015-02-10 20:15:53 -05001// Copyright 2015 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "xmpp/xmpp_client.h"
6
7#include <arpa/inet.h>
8#include <netdb.h>
9#include <netinet/in.h>
10#include <unistd.h>
11
12#include <string>
13
14#include <base/files/file_util.h>
15#include <chromeos/data_encoding.h>
16#include <chromeos/syslog_logging.h>
17
18namespace buffet {
19
20namespace {
21
22std::string BuildXmppStartStreamCommand() {
23 return "<stream:stream to='clouddevices.gserviceaccount.com' "
24 "xmlns:stream='http://etherx.jabber.org/streams' "
25 "xml:lang='*' version='1.0' xmlns='jabber:client'>";
26}
27
28std::string BuildXmppAuthenticateCommand(
29 const std::string& account, const std::string& token) {
30 chromeos::Blob credentials;
31 credentials.push_back(0);
32 credentials.insert(credentials.end(), account.begin(), account.end());
33 credentials.push_back(0);
34 credentials.insert(credentials.end(), token.begin(), token.end());
35 std::string msg = "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' "
36 "mechanism='X-OAUTH2' auth:service='oauth2' "
37 "auth:allow-non-google-login='true' "
38 "auth:client-uses-full-bind-result='true' "
39 "xmlns:auth='http://www.google.com/talk/protocol/auth'>" +
40 chromeos::data_encoding::Base64Encode(credentials) +
41 "</auth>";
42 return msg;
43}
44
45std::string BuildXmppBindCommand() {
46 return "<iq type='set' id='0'>"
47 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>";
48}
49
50std::string BuildXmppStartSessionCommand() {
51 return "<iq type='set' id='1'>"
52 "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>";
53}
54
55std::string BuildXmppSubscribeCommand(const std::string& account) {
56 return "<iq type='set' to='" + account + "' "
57 "id='pushsubscribe1'><subscribe xmlns='google:push'>"
58 "<item channel='cloud_devices' from=''/>"
59 "</subscribe></iq>";
60}
61
62} // namespace
63
Nathan Bullockf12f7f02015-02-20 14:46:53 -050064bool XmppClient::Read() {
Nathan Bullockbdabded2015-02-10 20:15:53 -050065 std::string msg;
66 if (!connection_->Read(&msg) || msg.size() <= 0) {
Nathan Bullockf12f7f02015-02-20 14:46:53 -050067 LOG(ERROR) << "Failed to read from stream. The socket was probably closed";
68 return false;
Nathan Bullockbdabded2015-02-10 20:15:53 -050069 }
70
71 // TODO(nathanbullock): Need to add support for TLS (brillo:191).
72 switch (state_) {
73 case XmppState::kStarted:
74 if (std::string::npos != msg.find(":features") &&
75 std::string::npos != msg.find("X-GOOGLE-TOKEN")) {
76 state_ = XmppState::kAuthenticationStarted;
77 connection_->Write(BuildXmppAuthenticateCommand(
78 account_, access_token_));
79 }
80 break;
81 case XmppState::kAuthenticationStarted:
82 if (std::string::npos != msg.find("success")) {
83 state_ = XmppState::kStreamRestartedPostAuthentication;
84 connection_->Write(BuildXmppStartStreamCommand());
Nathan Bullockf12f7f02015-02-20 14:46:53 -050085 } else if (std::string::npos != msg.find("not-authorized")) {
86 state_ = XmppState::kAuthenticationFailed;
87 return false;
Nathan Bullockbdabded2015-02-10 20:15:53 -050088 }
89 break;
90 case XmppState::kStreamRestartedPostAuthentication:
91 if (std::string::npos != msg.find(":features") &&
92 std::string::npos != msg.find(":xmpp-session")) {
93 state_ = XmppState::kBindSent;
94 connection_->Write(BuildXmppBindCommand());
95 }
96 break;
97 case XmppState::kBindSent:
98 if (std::string::npos != msg.find("iq") &&
99 std::string::npos != msg.find("result")) {
100 state_ = XmppState::kSessionStarted;
101 connection_->Write(BuildXmppStartSessionCommand());
102 }
103 break;
104 case XmppState::kSessionStarted:
105 if (std::string::npos != msg.find("iq") &&
106 std::string::npos != msg.find("result")) {
107 state_ = XmppState::kSubscribeStarted;
108 connection_->Write(BuildXmppSubscribeCommand(account_));
109 }
110 break;
111 case XmppState::kSubscribeStarted:
112 if (std::string::npos != msg.find("iq") &&
113 std::string::npos != msg.find("result")) {
114 state_ = XmppState::kSubscribed;
115 }
116 break;
117 default:
118 break;
119 }
Nathan Bullockf12f7f02015-02-20 14:46:53 -0500120 return true;
Nathan Bullockbdabded2015-02-10 20:15:53 -0500121}
122
123void XmppClient::StartStream() {
124 state_ = XmppState::kStarted;
125 connection_->Write(BuildXmppStartStreamCommand());
126}
127
128} // namespace buffet