Android Open Source - ubihelper Protocol Manager






From Project

Back to project page ubihelper.

License

The source code is released under:

GNU General Public License

If you think the Android project ubihelper listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
 * Copyright (c) 2012 The University of Nottingham
 * //w w  w  .  j av a  2s . c om
 * This file is part of ubihelper
 *
 *  ubihelper is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  ubihelper is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with ubihelper. If not, see <http://www.gnu.org/licenses/>.
 *  
 *  @author Chris Greenhalgh (cmg@cs.nott.ac.uk), The University of Nottingham
 */
package uk.ac.horizon.ubihelper.protocol;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Random;
import java.util.logging.Logger;

import org.json.JSONException;
import org.json.JSONObject;

import uk.ac.horizon.ubihelper.net.Message;
import uk.ac.horizon.ubihelper.net.OnPeerConnectionListener;
import uk.ac.horizon.ubihelper.net.PeerConnection;

/** Home for peer protocol logic/state machine.
 * 
 * @author cmg
 *
 */
public abstract class ProtocolManager {
  static Logger logger = Logger.getLogger(ProtocolManager.class.getName());
  
  private SecureRandom srandom;
  private Random random;
  private MessageDigest messageDigest;
  
  private static final String KEY_IMEI = "imei";
  private static final String KEY_WIFIMAC = "wifimac";
  private static final String KEY_BTMAC = "btmac";


  public ProtocolManager() {
    random = new Random(System.currentTimeMillis());
    try {
      srandom = SecureRandom.getInstance("SHA1PRNG");
    }
    catch (Exception e) {
      logger.warning("Could not get SecureRandom: "+e);
    }
    try {
      messageDigest = MessageDigest.getInstance("MD5");
    }
    catch (Exception e) {
      logger.warning("Could not get MessageDigest: "+e);
    }

  }
  
  public void getRandom(byte buf[]) {
    if (srandom!=null)
      srandom.nextBytes(buf);
    else
      random.nextBytes(buf);
  }

  public static class ClientConnectionListener implements OnPeerConnectionListener {
    private ProtocolManager pm;
    public ClientConnectionListener(ProtocolManager pm) {
      this.pm = pm;
    }
    public void onRecvMessage(PeerConnection pc) {
      if (pc.attachment() instanceof ClientInfo) {
        ClientInfo ci = (ClientInfo)pc.attachment();
        logger.info("onMessage ClientInfo "+ci);
        pm.clientCheckMessages(ci);
      } else if (pc.attachment() instanceof PeerInfo) {
        PeerInfo pi = (PeerInfo)pc.attachment();
        logger.info("onMessage PeerInfo "+pi.id);
        pm.checkPeerMessages(pi);
      }
    }
    
    public void onFail(PeerConnection pc, boolean sendFailed,
        boolean recvFailed, boolean connectFailed) {
      if (pc.attachment() instanceof ClientInfo) {
        ClientInfo ci = (ClientInfo)pc.attachment();
        logger.info("onFail ClientInfo "+ci);
        // TODO
      }
      else if (pc.attachment() instanceof PeerInfo) {
        PeerInfo pi = (PeerInfo)pc.attachment();
        logger.info("onFail PeerInfo "+pi.id);
        pc.attach(null);
        pm.peerHandleFailed(pi);
      }
    }

    public void onConnected(PeerConnection pc) {
    }
  }

  /** called on indication of avilable messages at client */ 
  private void clientCheckMessages(ClientInfo ci) {
    Message m = null;
    Object msg;
    try {
      while ((m=ci.pc.getMessage())!=null) {
        switch (ci.state) {
        case STATE_NEGOTIATE_PROTOCOL: {
          boolean ok = MessageUtils.checkNegotiateProtocolResponse(m);
          if (!ok) {
            removeClient(ci);
            return;
          }
          ci.pc.sendMessage(MessageUtils.getHelloMessage());
          ci.state = ClientState.STATE_NEGOTIATED_PROTOCOL;
          break;
        }
        case STATE_NEGOTIATED_PROTOCOL: {
          msg = MessageUtils.parseManagementMessage(m);
          if (msg instanceof MessageUtils.InitPeerReq) {
            MessageUtils.InitPeerReq req = (MessageUtils.InitPeerReq)msg;
            if (!clientHandlePeerReq(ci, req))
              return;
          }
          else 
            throw new IOException("Received first management message of type "+msg.getClass().getName());
          break;
        }
        case STATE_PEER_PIN: {
          msg = MessageUtils.parseManagementMessage(m);
          if (msg instanceof MessageUtils.InitPeerDone) {
            MessageUtils.InitPeerDone req = (MessageUtils.InitPeerDone)msg;
            if (!clientHandlePeerPinResponse(ci, req))
              return;
          }
          else 
            throw new IOException("Received peer_pin response of type "+msg.getClass().getName());
          break;
        }
        }
      }
    }
    catch (Exception e) {
      logger.warning("Error handling client message: "+e);
      e.printStackTrace();
      removeClient(ci);
    }
  }

  public void checkPeerMessages(PeerInfo pi) {
    // TODO Auto-generated method stub
    while (true) {
      Message m = pi.pc.getMessage();
      if (m==null)
        return;
      logger.info("Received message "+m);
      // TODO
    }
  }

  public void removeClient(ClientInfo ci) {
    try {
      ci.pc.close();
    }
    catch (Exception e) {
      /* ignore */
    }
  }
  /** called from handleFirstMessage on receipt of init_peer_req message by client */
  private boolean clientHandlePeerReq(ClientInfo ci, MessageUtils.InitPeerReq req) {
    ci.id = req.id;
    ci.name = req.name;
    ci.port = req.port;
    ci.pindigest = req.pindigest;
    boolean prompted = clientPromptForPin(ci);
    if (prompted) {
      ci.state = ClientState.STATE_WAITING_FOR_PIN;
      return true;
    }
    else {
      // can't do pin!
      // send response
      ci.secret2 = getSecret();
      Message r = MessageUtils.getRespPeerNopin(getId(), getPort(), getName(), getInfo(), ci.secret2);
      ci.pc.sendMessage(r);

      ci.state = ClientState.STATE_PEERED;

      //  sub-class handle peered
      return clientHandlePeered(ci);
    }
  }

  /** prompt for PIN, e.g. from user. return false (default) if cannot prompt. */
  protected boolean clientPromptForPin(ClientInfo ci) {
    return false;
  }
  protected abstract byte [] base64Decode(String str);
  protected abstract String base64Encode(byte [] bs);

  /** called on receipt of message after resp_peer_pin by client */
  private boolean clientHandlePeerPinResponse(ClientInfo ci, MessageUtils.InitPeerDone rec) {
    ci.pinnonce = rec.pinnonce;
    ci.peerInfo = rec.info;
    ci.secret1 = rec.secret;
    logger.warning("Received init_peer_done in state peer_pin with info="+ci.peerInfo);
    // check pin
    try {
      byte nbuf[] = base64Decode(ci.pinnonce);
      messageDigest.reset();
      messageDigest.update(nbuf);
      messageDigest.update(ci.pin.getBytes("UTF-8"));
      byte dbuf[] = messageDigest.digest();
      String pindigest = base64Encode(dbuf);
      if (!ci.pindigest.equals(pindigest)) {
        logger.warning("Reject peer with incorrect pindigest");
        removeClient(ci);
        return false;
      }
    } catch (UnsupportedEncodingException e) {
      // shouldn't happen!
      logger.warning("Unsupported encoding (shoulnd't be): "+e);
    }
    // send response
    ci.secret2 = getSecret();
    Message r = MessageUtils.getRespPeerDone(getInfo(), ci.secret2);
    ci.pc.sendMessage(r);

    ci.state = ClientState.STATE_PEERED;

    //  sub-class handle peered
    return clientHandlePeered(ci);
  }
  private String getSecret() {
    byte sbuf[] = new byte[8];
    getRandom(sbuf);
    return base64Encode(sbuf);
  }
  public String combineSecrets(String secret1, String secret2) {
    int len = 0;
    if (secret1==null) {
      if (secret2==null)
        return null;
      logger.warning("combineSecrets with secret1==null");
      return secret2;
    }
    if (secret2==null) {
      logger.warning("combineSecrets with secret2==null");
      return secret1;      
    }
    byte bs1[] = base64Decode(secret1);
    byte bs2[] = base64Decode(secret2);
    len = bs1.length;
    if (bs2.length > bs1.length) {
      byte bt[] = bs1;
      bs1 = bs2;
      bs2 = bt;
    }
    // shorter in bs2; XOR for now!
    for (int i=0; i<bs2.length; i++) 
      bs1[i] = (byte)(bs1[i] ^ bs2[i]);

    return base64Encode(bs1);
  }

  
  /** called when successfully peered */
  protected boolean clientHandlePeered(ClientInfo ci) {
    // convert to PeerInfo
    PeerInfo pi = new PeerInfo();
    pi.createdTimestamp = System.currentTimeMillis();
    pi.info = ci.peerInfo;
    if (pi.info!=null) {
      try {
        if (pi.info.has(KEY_BTMAC))
          pi.btmac = pi.info.getString(KEY_BTMAC);
        if (pi.info.has(KEY_WIFIMAC))
          pi.wifimac = pi.info.getString(KEY_WIFIMAC);
        if (pi.info.has(KEY_IMEI))
          pi.imei = pi.info.getString(KEY_IMEI);
      }
      catch (JSONException e) {
        logger.warning("Unexpected JSON error unpacking peerInfo: "+e);
      }
    }
    pi.secret = combineSecrets(ci.secret1, ci.secret2);
    pi.ip = ci.pc.getSocketChannel().socket().getInetAddress().getHostAddress();
    pi.ipTimestamp = System.currentTimeMillis();
    pi.port = ci.pc.getSocketChannel().socket().getPort();
    pi.portTimestamp = pi.ipTimestamp;
    pi.name = ci.name;
    pi.id = ci.id;
    pi.trusted = true;
    pi.nickname = pi.name;
    logger.info("Converted ClientInfo to PeerInfo");

    pi.pc = ci.pc;
    if (pi.pc!=null)
      pi.pc.attach(pi);

    //      peerCache.put(pi.id, pi);
    //      pi.pc.attach(pi);
    //
    //      Intent i = new Intent(ACTION_PEER_REQUESTS_CHANGED);
    //      service.sendBroadcast(i);

    // don't handle more messages as a client
    return clientHandlePeered(ci, pi);
  }

  protected abstract boolean clientHandlePeered(ClientInfo ci, PeerInfo pi);
  protected abstract void peerHandleFailed(PeerInfo pi);


  protected abstract JSONObject getInfo();
  protected abstract String getName();
  protected abstract int getPort();
  protected abstract String getId();
}




Java Source Code List

org.json.JSONArray.java
org.json.JSONException.java
org.json.JSONObject.java
org.json.JSONString.java
org.json.JSONStringer.java
org.json.JSONTokener.java
org.json.JSONWriter.java
uk.ac.horizon.ubihelper.channel.ChannelFactory.java
uk.ac.horizon.ubihelper.channel.ChannelListener.java
uk.ac.horizon.ubihelper.channel.ChannelManager.java
uk.ac.horizon.ubihelper.channel.ChannelValueEvent.java
uk.ac.horizon.ubihelper.channel.NamedChannel.java
uk.ac.horizon.ubihelper.channel.PullSubscription.java
uk.ac.horizon.ubihelper.channel.SharedVariableChannel.java
uk.ac.horizon.ubihelper.channel.Subscription.java
uk.ac.horizon.ubihelper.dns.DnsClient.java
uk.ac.horizon.ubihelper.dns.DnsProtocol.java
uk.ac.horizon.ubihelper.dns.DnsServer.java
uk.ac.horizon.ubihelper.dns.DnsUtils.java
uk.ac.horizon.ubihelper.httpserver.HttpClientHandler.java
uk.ac.horizon.ubihelper.httpserver.HttpContinuation.java
uk.ac.horizon.ubihelper.httpserver.HttpError.java
uk.ac.horizon.ubihelper.httpserver.HttpListener.java
uk.ac.horizon.ubihelper.j2se.Base64.java
uk.ac.horizon.ubihelper.j2se.Server.java
uk.ac.horizon.ubihelper.net.Fragment.java
uk.ac.horizon.ubihelper.net.Marshaller.java
uk.ac.horizon.ubihelper.net.Message.java
uk.ac.horizon.ubihelper.net.OnPeerConnectionListener.java
uk.ac.horizon.ubihelper.net.PeerConnectionScheduler.java
uk.ac.horizon.ubihelper.net.PeerConnection.java
uk.ac.horizon.ubihelper.protocol.ClientInfo.java
uk.ac.horizon.ubihelper.protocol.ClientState.java
uk.ac.horizon.ubihelper.protocol.MessageUtils.java
uk.ac.horizon.ubihelper.protocol.PeerInfo.java
uk.ac.horizon.ubihelper.protocol.ProtocolManager.java
uk.ac.horizon.ubihelper.service.BroadcastIntentSubscription.java
uk.ac.horizon.ubihelper.service.EnabledPeersChannel.java
uk.ac.horizon.ubihelper.service.LogManager.java
uk.ac.horizon.ubihelper.service.LogSubscription.java
uk.ac.horizon.ubihelper.service.PeerManager.java
uk.ac.horizon.ubihelper.service.PeersOpenHelper.java
uk.ac.horizon.ubihelper.service.Service.java
uk.ac.horizon.ubihelper.service.WifiDiscoveryManager.java
uk.ac.horizon.ubihelper.service.channel.BluetoothDiscoveryChannel.java
uk.ac.horizon.ubihelper.service.channel.CellLocationChannel.java
uk.ac.horizon.ubihelper.service.channel.CellStrengthChannel.java
uk.ac.horizon.ubihelper.service.channel.GpsStatusChannel.java
uk.ac.horizon.ubihelper.service.channel.LocationChannel.java
uk.ac.horizon.ubihelper.service.channel.MicChannel.java
uk.ac.horizon.ubihelper.service.channel.PollingChannel.java
uk.ac.horizon.ubihelper.service.channel.SensorChannel.java
uk.ac.horizon.ubihelper.service.channel.TimeChannel.java
uk.ac.horizon.ubihelper.service.channel.WifiScannerChannel.java
uk.ac.horizon.ubihelper.ui.AboutActivity.java
uk.ac.horizon.ubihelper.ui.ChannelListActivity.java
uk.ac.horizon.ubihelper.ui.ChannelPeerListActivity.java
uk.ac.horizon.ubihelper.ui.ChannelValueActivity.java
uk.ac.horizon.ubihelper.ui.ChannelViewActivity.java
uk.ac.horizon.ubihelper.ui.LoggingChannelListActivity.java
uk.ac.horizon.ubihelper.ui.LoggingPreferences.java
uk.ac.horizon.ubihelper.ui.MainPreferences.java
uk.ac.horizon.ubihelper.ui.ManagePeersActivity.java
uk.ac.horizon.ubihelper.ui.PeerInfoActivity.java
uk.ac.horizon.ubihelper.ui.PeerManualAddActivity.java
uk.ac.horizon.ubihelper.ui.PeerRequestActivity.java
uk.ac.horizon.ubihelper.ui.PeerRequestInfoActivity.java
uk.ac.horizon.ubihelper.ui.SearchPeersActivity.java
uk.ac.horizon.ubihelper.ui.TestActivity.java
uk.ac.horizon.ubihelper.ui.WifiStatusActivity.java
uk.ac.horizon.ubihelper.websocket.ClientWebsocket.java
uk.ac.horizon.ubihelper.websocket.ReadyState.java
uk.ac.horizon.ubihelper.websocket.SocketChannelWebsocket.java
uk.ac.horizon.ubihelper.websocket.WebsocketListener.java
uk.ac.horizon.ubihelper.websocket.Websocket.java