Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-6212] Android: Add Support for TLS to TCP Sockets

GitHub Issuen/a
TypeNew Feature
PriorityLow
StatusOpen
ResolutionUnresolved
Affected Version/sRelease 1.8.0.1
Fix Version/sn/a
ComponentsAndroid
Labelsexalture
ReporterShak Hossain
AssigneeEric Merriman
Created2011-11-17T07:23:38.000+0000
Updated2018-08-02T17:31:47.000+0000

Description

Problem

Facebook chat now requires a secure connection, so any apps that are using it are now broken until TLS is exposed through our TCP sockets.

Pull Request

https://github.com/appcelerator/titanium_mobile/pull/726

How to Test

Drop the following in an app.js. Look at the log. After some network traffic (~5 seconds) you should see the log message, "Socket secured!". (Note that around 10 seconds later, the connection will timeout and you'll be disconnected -- this is expected behavior.)
var win = Ti.UI.createWindow({
    backgroundColor: '#fff'
});

var states = {
    WAITING_FOR_FIRST_RESPONSE: 0,
    WAITING_FOR_START_TLS: 1,
    WAITING_FOR_PROCEED: 2,
    WAITING_FOR_SECURED: 3,
    DONE: 4,
    ERRORED: 5
};
var currentState = Ti.Android ? states.WAITING_FOR_FIRST_RESPONSE : states.WAITING_FOR_START_TLS;

var socket = Ti.Network.Socket.createTCP({
    host: 'chat.facebook.com', port: 5222,
    connected: function (e) {
        Ti.API.info('Socket opened!');
        Ti.Stream.pump(e.socket, read, 1024, true);
        socket.write(Ti.createBuffer({
            value: '<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" \
                xmlns="jabber:client" to="chat.facebook.com" xml:lang="en" \
                xmlns:xml="http://www.w3.org/XML/1998/namespace">'
        }));
    },
    secured: function (e) {
        Ti.API.info('Socket secured!');
    },
    error: function (e) {
        Ti.API.info('Error (' + e.errorCode + '): ' + e.error);
    },
    closed: function (e) {
        Ti.API.info('Socket closed!');
    }
});
socket.connect();

function write(msg) {
    Ti.API.info('State: ' + currentState + ', Wrote: ' + msg);
    socket.write(Ti.createBuffer({
        value: msg
    }));
}

function read(e) {
    try {
        if (e.buffer) {
            var received = e.buffer.toString();
            Ti.API.info('State: ' + currentState + ', Received: ' + received);
            switch (currentState) {

                case states.WAITING_FOR_FIRST_RESPONSE:
                    if (received.split('<?xml version="1.0"?><stream:stream ').length <= 1) {
                        Ti.API.error('Unexpected response from server while WAITING_FOR_FIRST_RESPONSE!');
                        return currentState = states.ERRORED;
                    }
                    return currentState = states.WAITING_FOR_START_TLS;

                case states.WAITING_FOR_START_TLS:
                    if (received.split('<stream:features><starttls ').length <= 1) {
                        Ti.API.error('Unexpected response from server while WAITING_FOR_START_TLS!');
                        return currentState = states.ERRORED;
                    }
                    write('<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>');
                    if (!Ti.Android) {
                        // Note: iOS requires that startTLS be called right after sending the above XML.
                        // This is required because of how reads and writes are queued up before a secure handshake.
                        socket.startTLS();
                        return currentState = states.WAITING_FOR_SECURED;
                    }
                    return currentState = states.WAITING_FOR_PROCEED;

                case states.WAITING_FOR_PROCEED:
                    if (received.split('<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>').length <= 1) {
                        Ti.API.error('Unexpected response from server while WAITING_FOR_PROCEED!');
                        return currentState = states.ERRORED;
                    }
                    socket.startTLS();
                    return currentState = states.WAITING_FOR_SECURED;

                case states.WAITING_FOR_SECURED:
                    write('<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" \
                        xmlns="jabber:client" to="chat.facebook.com" xml:lang="en" \
                        xmlns:xml="http://www.w3.org/XML/1998/namespace">');
                    return currentState = states.DONE;

            }
        }
        else {
            Ti.API.error('Error: no e.buffer!');
        }
    } catch (ex) {
        Ti.API.error(ex);
    }
}

win.open();

Related Tickets

iOS: [TIMOB-6211] Android: [TIMOB-6212] APIDoc: [TIMOB-6213]

Comments

  1. Dawson Toth 2011-11-17

    Opened pull request https://github.com/appcelerator/titanium_mobile/pull/726
  2. Dawson Toth 2011-11-17

    Revamped the description so that it is clear what this is addressing and how it can be tested.

JSON Source