tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RoomParametersFetcher.java (8986B)


      1 /*
      2 *  Copyright 2014 The WebRTC Project Authors. All rights reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 package org.appspot.apprtc;
     12 
     13 import android.util.Log;
     14 import java.io.IOException;
     15 import java.io.InputStream;
     16 import java.net.HttpURLConnection;
     17 import java.net.URL;
     18 import java.util.ArrayList;
     19 import java.util.Scanner;
     20 import java.util.List;
     21 import org.appspot.apprtc.AppRTCClient.SignalingParameters;
     22 import org.appspot.apprtc.util.AsyncHttpURLConnection;
     23 import org.appspot.apprtc.util.AsyncHttpURLConnection.AsyncHttpEvents;
     24 import org.json.JSONArray;
     25 import org.json.JSONException;
     26 import org.json.JSONObject;
     27 import org.webrtc.IceCandidate;
     28 import org.webrtc.PeerConnection;
     29 import org.webrtc.SessionDescription;
     30 
     31 /**
     32 * AsyncTask that converts an AppRTC room URL into the set of signaling
     33 * parameters to use with that room.
     34 */
     35 public class RoomParametersFetcher {
     36  private static final String TAG = "RoomRTCClient";
     37  private static final int TURN_HTTP_TIMEOUT_MS = 5000;
     38  private final RoomParametersFetcherEvents events;
     39  private final String roomUrl;
     40  private final String roomMessage;
     41 
     42  /**
     43   * Room parameters fetcher callbacks.
     44   */
     45  public interface RoomParametersFetcherEvents {
     46    /**
     47     * Callback fired once the room's signaling parameters
     48     * SignalingParameters are extracted.
     49     */
     50    void onSignalingParametersReady(final SignalingParameters params);
     51 
     52    /**
     53     * Callback for room parameters extraction error.
     54     */
     55    void onSignalingParametersError(final String description);
     56  }
     57 
     58  public RoomParametersFetcher(
     59      String roomUrl, String roomMessage, final RoomParametersFetcherEvents events) {
     60    this.roomUrl = roomUrl;
     61    this.roomMessage = roomMessage;
     62    this.events = events;
     63  }
     64 
     65  public void makeRequest() {
     66    Log.d(TAG, "Connecting to room: " + roomUrl);
     67    AsyncHttpURLConnection httpConnection =
     68        new AsyncHttpURLConnection("POST", roomUrl, roomMessage, new AsyncHttpEvents() {
     69          @Override
     70          public void onHttpError(String errorMessage) {
     71            Log.e(TAG, "Room connection error: " + errorMessage);
     72            events.onSignalingParametersError(errorMessage);
     73          }
     74 
     75          @Override
     76          public void onHttpComplete(String response) {
     77            roomHttpResponseParse(response);
     78          }
     79        });
     80    httpConnection.send();
     81  }
     82 
     83  private void roomHttpResponseParse(String response) {
     84    Log.d(TAG, "Room response: " + response);
     85    try {
     86      List<IceCandidate> iceCandidates = null;
     87      SessionDescription offerSdp = null;
     88      JSONObject roomJson = new JSONObject(response);
     89 
     90      String result = roomJson.getString("result");
     91      if (!result.equals("SUCCESS")) {
     92        events.onSignalingParametersError("Room response error: " + result);
     93        return;
     94      }
     95      response = roomJson.getString("params");
     96      roomJson = new JSONObject(response);
     97      String roomId = roomJson.getString("room_id");
     98      String clientId = roomJson.getString("client_id");
     99      String wssUrl = roomJson.getString("wss_url");
    100      String wssPostUrl = roomJson.getString("wss_post_url");
    101      boolean initiator = roomJson.getBoolean("is_initiator");
    102      if (!initiator) {
    103        iceCandidates = new ArrayList<>();
    104        String messagesString = roomJson.getString("messages");
    105        JSONArray messages = new JSONArray(messagesString);
    106        for (int i = 0; i < messages.length(); ++i) {
    107          String messageString = messages.getString(i);
    108          JSONObject message = new JSONObject(messageString);
    109          String messageType = message.getString("type");
    110          Log.d(TAG, "GAE->C #" + i + " : " + messageString);
    111          if (messageType.equals("offer")) {
    112            offerSdp = new SessionDescription(
    113                SessionDescription.Type.fromCanonicalForm(messageType), message.getString("sdp"));
    114          } else if (messageType.equals("candidate")) {
    115            IceCandidate candidate = new IceCandidate(
    116                message.getString("id"), message.getInt("label"), message.getString("candidate"));
    117            iceCandidates.add(candidate);
    118          } else {
    119            Log.e(TAG, "Unknown message: " + messageString);
    120          }
    121        }
    122      }
    123      Log.d(TAG, "RoomId: " + roomId + ". ClientId: " + clientId);
    124      Log.d(TAG, "Initiator: " + initiator);
    125      Log.d(TAG, "WSS url: " + wssUrl);
    126      Log.d(TAG, "WSS POST url: " + wssPostUrl);
    127 
    128      List<PeerConnection.IceServer> iceServers =
    129          iceServersFromPCConfigJSON(roomJson.getString("pc_config"));
    130      boolean isTurnPresent = false;
    131      for (PeerConnection.IceServer server : iceServers) {
    132        Log.d(TAG, "IceServer: " + server);
    133        for (String uri : server.urls) {
    134          if (uri.startsWith("turn:")) {
    135            isTurnPresent = true;
    136            break;
    137          }
    138        }
    139      }
    140      // Request TURN servers.
    141      if (!isTurnPresent && !roomJson.optString("ice_server_url").isEmpty()) {
    142        List<PeerConnection.IceServer> turnServers =
    143            requestTurnServers(roomJson.getString("ice_server_url"));
    144        for (PeerConnection.IceServer turnServer : turnServers) {
    145          Log.d(TAG, "TurnServer: " + turnServer);
    146          iceServers.add(turnServer);
    147        }
    148      }
    149 
    150      SignalingParameters params = new SignalingParameters(
    151          iceServers, initiator, clientId, wssUrl, wssPostUrl, offerSdp, iceCandidates);
    152      events.onSignalingParametersReady(params);
    153    } catch (JSONException e) {
    154      events.onSignalingParametersError("Room JSON parsing error: " + e.toString());
    155    } catch (IOException e) {
    156      events.onSignalingParametersError("Room IO error: " + e.toString());
    157    }
    158  }
    159 
    160  // Requests & returns a TURN ICE Server based on a request URL.  Must be run
    161  // off the main thread!
    162  @SuppressWarnings("UseNetworkAnnotations")
    163  private List<PeerConnection.IceServer> requestTurnServers(String url)
    164      throws IOException, JSONException {
    165    List<PeerConnection.IceServer> turnServers = new ArrayList<>();
    166    Log.d(TAG, "Request TURN from: " + url);
    167    HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
    168    connection.setDoOutput(true);
    169    connection.setRequestProperty("REFERER", "https://appr.tc");
    170    connection.setConnectTimeout(TURN_HTTP_TIMEOUT_MS);
    171    connection.setReadTimeout(TURN_HTTP_TIMEOUT_MS);
    172    int responseCode = connection.getResponseCode();
    173    if (responseCode != 200) {
    174      throw new IOException("Non-200 response when requesting TURN server from " + url + " : "
    175          + connection.getHeaderField(null));
    176    }
    177    InputStream responseStream = connection.getInputStream();
    178    String response = drainStream(responseStream);
    179    connection.disconnect();
    180    Log.d(TAG, "TURN response: " + response);
    181    JSONObject responseJSON = new JSONObject(response);
    182    JSONArray iceServers = responseJSON.getJSONArray("iceServers");
    183    for (int i = 0; i < iceServers.length(); ++i) {
    184      JSONObject server = iceServers.getJSONObject(i);
    185      JSONArray turnUrls = server.getJSONArray("urls");
    186      String username = server.has("username") ? server.getString("username") : "";
    187      String credential = server.has("credential") ? server.getString("credential") : "";
    188      for (int j = 0; j < turnUrls.length(); j++) {
    189        String turnUrl = turnUrls.getString(j);
    190        PeerConnection.IceServer turnServer =
    191            PeerConnection.IceServer.builder(turnUrl)
    192              .setUsername(username)
    193              .setPassword(credential)
    194              .createIceServer();
    195        turnServers.add(turnServer);
    196      }
    197    }
    198    return turnServers;
    199  }
    200 
    201  // Return the list of ICE servers described by a WebRTCPeerConnection
    202  // configuration string.
    203  private List<PeerConnection.IceServer> iceServersFromPCConfigJSON(String pcConfig)
    204      throws JSONException {
    205    JSONObject json = new JSONObject(pcConfig);
    206    JSONArray servers = json.getJSONArray("iceServers");
    207    List<PeerConnection.IceServer> ret = new ArrayList<>();
    208    for (int i = 0; i < servers.length(); ++i) {
    209      JSONObject server = servers.getJSONObject(i);
    210      String url = server.getString("urls");
    211      String credential = server.has("credential") ? server.getString("credential") : "";
    212        PeerConnection.IceServer turnServer =
    213            PeerConnection.IceServer.builder(url)
    214              .setPassword(credential)
    215              .createIceServer();
    216      ret.add(turnServer);
    217    }
    218    return ret;
    219  }
    220 
    221  // Return the contents of an InputStream as a String.
    222  private static String drainStream(InputStream in) {
    223    Scanner s = new Scanner(in, "UTF-8").useDelimiter("\\A");
    224    return s.hasNext() ? s.next() : "";
    225  }
    226 }