blob: 6f60380bff1988ccd1359328bb107e8e00a08111 [file] [log] [blame]
tkchin@webrtc.org87776a82014-12-09 19:32:351/*
Donald E Curtisa8736442015-08-05 22:48:132 * Copyright 2014 The WebRTC Project Authors. All rights reserved.
tkchin@webrtc.org87776a82014-12-09 19:32:353 *
Donald E Curtisa8736442015-08-05 22:48:134 * 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.
tkchin@webrtc.org87776a82014-12-09 19:32:359 */
10
11#import "ARDWebSocketChannel.h"
12
tkchin9eeb6242016-04-27 08:54:2013#import "WebRTC/RTCLogging.h"
tkchin@webrtc.org87776a82014-12-09 19:32:3514#import "SRWebSocket.h"
15
haysc913e6452015-10-02 18:44:0316#import "ARDSignalingMessage.h"
tkchinc3f46a92015-07-23 19:50:5517#import "ARDUtilities.h"
18
tkchin@webrtc.org87776a82014-12-09 19:32:3519// TODO(tkchin): move these to a configuration object.
20static NSString const *kARDWSSMessageErrorKey = @"error";
21static NSString const *kARDWSSMessagePayloadKey = @"msg";
22
23@interface ARDWebSocketChannel () <SRWebSocketDelegate>
24@end
25
26@implementation ARDWebSocketChannel {
27 NSURL *_url;
28 NSURL *_restURL;
29 SRWebSocket *_socket;
30}
31
32@synthesize delegate = _delegate;
33@synthesize state = _state;
34@synthesize roomId = _roomId;
35@synthesize clientId = _clientId;
36
37- (instancetype)initWithURL:(NSURL *)url
38 restURL:(NSURL *)restURL
tkchin@webrtc.org3a63a3c2015-01-06 07:21:3439 delegate:(id<ARDSignalingChannelDelegate>)delegate {
tkchin@webrtc.org87776a82014-12-09 19:32:3540 if (self = [super init]) {
41 _url = url;
42 _restURL = restURL;
43 _delegate = delegate;
44 _socket = [[SRWebSocket alloc] initWithURL:url];
45 _socket.delegate = self;
tkchinc3f46a92015-07-23 19:50:5546 RTCLog(@"Opening WebSocket.");
tkchin@webrtc.org87776a82014-12-09 19:32:3547 [_socket open];
48 }
49 return self;
50}
51
52- (void)dealloc {
53 [self disconnect];
54}
55
tkchin@webrtc.org3a63a3c2015-01-06 07:21:3456- (void)setState:(ARDSignalingChannelState)state {
tkchin@webrtc.org87776a82014-12-09 19:32:3557 if (_state == state) {
58 return;
59 }
60 _state = state;
61 [_delegate channel:self didChangeState:_state];
62}
63
64- (void)registerForRoomId:(NSString *)roomId
65 clientId:(NSString *)clientId {
66 NSParameterAssert(roomId.length);
67 NSParameterAssert(clientId.length);
68 _roomId = roomId;
69 _clientId = clientId;
tkchin@webrtc.org3a63a3c2015-01-06 07:21:3470 if (_state == kARDSignalingChannelStateOpen) {
tkchin@webrtc.org87776a82014-12-09 19:32:3571 [self registerWithCollider];
72 }
73}
74
tkchin@webrtc.org3a63a3c2015-01-06 07:21:3475- (void)sendMessage:(ARDSignalingMessage *)message {
tkchin@webrtc.org87776a82014-12-09 19:32:3576 NSParameterAssert(_clientId.length);
77 NSParameterAssert(_roomId.length);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:3478 NSData *data = [message JSONData];
79 if (_state == kARDSignalingChannelStateRegistered) {
tkchin@webrtc.org87776a82014-12-09 19:32:3580 NSString *payload =
81 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
82 NSDictionary *message = @{
83 @"cmd": @"send",
84 @"msg": payload,
85 };
86 NSData *messageJSONObject =
87 [NSJSONSerialization dataWithJSONObject:message
88 options:NSJSONWritingPrettyPrinted
89 error:nil];
90 NSString *messageString =
91 [[NSString alloc] initWithData:messageJSONObject
92 encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 19:50:5593 RTCLog(@"C->WSS: %@", messageString);
tkchin@webrtc.org87776a82014-12-09 19:32:3594 [_socket send:messageString];
95 } else {
96 NSString *dataString =
97 [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 19:50:5598 RTCLog(@"C->WSS POST: %@", dataString);
tkchin@webrtc.org87776a82014-12-09 19:32:3599 NSString *urlString =
100 [NSString stringWithFormat:@"%@/%@/%@",
101 [_restURL absoluteString], _roomId, _clientId];
102 NSURL *url = [NSURL URLWithString:urlString];
103 [NSURLConnection sendAsyncPostToURL:url
104 withData:data
105 completionHandler:nil];
106 }
107}
108
109- (void)disconnect {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34110 if (_state == kARDSignalingChannelStateClosed ||
111 _state == kARDSignalingChannelStateError) {
tkchin@webrtc.org87776a82014-12-09 19:32:35112 return;
113 }
114 [_socket close];
tkchinc3f46a92015-07-23 19:50:55115 RTCLog(@"C->WSS DELETE rid:%@ cid:%@", _roomId, _clientId);
tkchin@webrtc.org87776a82014-12-09 19:32:35116 NSString *urlString =
117 [NSString stringWithFormat:@"%@/%@/%@",
118 [_restURL absoluteString], _roomId, _clientId];
119 NSURL *url = [NSURL URLWithString:urlString];
120 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
121 request.HTTPMethod = @"DELETE";
122 request.HTTPBody = nil;
123 [NSURLConnection sendAsyncRequest:request completionHandler:nil];
124}
125
126#pragma mark - SRWebSocketDelegate
127
128- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
tkchinc3f46a92015-07-23 19:50:55129 RTCLog(@"WebSocket connection opened.");
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34130 self.state = kARDSignalingChannelStateOpen;
tkchin@webrtc.org87776a82014-12-09 19:32:35131 if (_roomId.length && _clientId.length) {
132 [self registerWithCollider];
133 }
134}
135
136- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
137 NSString *messageString = message;
138 NSData *messageData = [messageString dataUsingEncoding:NSUTF8StringEncoding];
139 id jsonObject = [NSJSONSerialization JSONObjectWithData:messageData
140 options:0
141 error:nil];
142 if (![jsonObject isKindOfClass:[NSDictionary class]]) {
tkchinc3f46a92015-07-23 19:50:55143 RTCLogError(@"Unexpected message: %@", jsonObject);
tkchin@webrtc.org87776a82014-12-09 19:32:35144 return;
145 }
146 NSDictionary *wssMessage = jsonObject;
147 NSString *errorString = wssMessage[kARDWSSMessageErrorKey];
148 if (errorString.length) {
tkchinc3f46a92015-07-23 19:50:55149 RTCLogError(@"WSS error: %@", errorString);
tkchin@webrtc.org87776a82014-12-09 19:32:35150 return;
151 }
152 NSString *payload = wssMessage[kARDWSSMessagePayloadKey];
153 ARDSignalingMessage *signalingMessage =
154 [ARDSignalingMessage messageFromJSONString:payload];
tkchinc3f46a92015-07-23 19:50:55155 RTCLog(@"WSS->C: %@", payload);
tkchin@webrtc.org87776a82014-12-09 19:32:35156 [_delegate channel:self didReceiveMessage:signalingMessage];
157}
158
159- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
tkchinc3f46a92015-07-23 19:50:55160 RTCLogError(@"WebSocket error: %@", error);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34161 self.state = kARDSignalingChannelStateError;
tkchin@webrtc.org87776a82014-12-09 19:32:35162}
163
164- (void)webSocket:(SRWebSocket *)webSocket
165 didCloseWithCode:(NSInteger)code
166 reason:(NSString *)reason
167 wasClean:(BOOL)wasClean {
tkchinc3f46a92015-07-23 19:50:55168 RTCLog(@"WebSocket closed with code: %ld reason:%@ wasClean:%d",
tkchin@webrtc.org87776a82014-12-09 19:32:35169 (long)code, reason, wasClean);
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34170 NSParameterAssert(_state != kARDSignalingChannelStateError);
171 self.state = kARDSignalingChannelStateClosed;
tkchin@webrtc.org87776a82014-12-09 19:32:35172}
173
174#pragma mark - Private
175
176- (void)registerWithCollider {
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34177 if (_state == kARDSignalingChannelStateRegistered) {
tkchin@webrtc.org87776a82014-12-09 19:32:35178 return;
179 }
180 NSParameterAssert(_roomId.length);
181 NSParameterAssert(_clientId.length);
182 NSDictionary *registerMessage = @{
183 @"cmd": @"register",
184 @"roomid" : _roomId,
185 @"clientid" : _clientId,
186 };
187 NSData *message =
188 [NSJSONSerialization dataWithJSONObject:registerMessage
189 options:NSJSONWritingPrettyPrinted
190 error:nil];
191 NSString *messageString =
192 [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
tkchinc3f46a92015-07-23 19:50:55193 RTCLog(@"Registering on WSS for rid:%@ cid:%@", _roomId, _clientId);
tkchin@webrtc.org87776a82014-12-09 19:32:35194 // Registration can fail if server rejects it. For example, if the room is
195 // full.
196 [_socket send:messageString];
tkchin@webrtc.org3a63a3c2015-01-06 07:21:34197 self.state = kARDSignalingChannelStateRegistered;
tkchin@webrtc.org87776a82014-12-09 19:32:35198}
199
200@end
haysc913e6452015-10-02 18:44:03201
202@interface ARDLoopbackWebSocketChannel () <ARDSignalingChannelDelegate>
203@end
204
205@implementation ARDLoopbackWebSocketChannel
206
207- (instancetype)initWithURL:(NSURL *)url restURL:(NSURL *)restURL {
208 return [super initWithURL:url restURL:restURL delegate:self];
209}
210
211#pragma mark - ARDSignalingChannelDelegate
212
213- (void)channel:(id<ARDSignalingChannel>)channel
214 didReceiveMessage:(ARDSignalingMessage *)message {
215 switch (message.type) {
216 case kARDSignalingMessageTypeOffer: {
217 // Change message to answer, send back to server.
218 ARDSessionDescriptionMessage *sdpMessage =
219 (ARDSessionDescriptionMessage *)message;
220 RTCSessionDescription *description = sdpMessage.sessionDescription;
hjon79858f82016-03-14 05:08:26221 NSString *dsc = description.sdp;
haysc913e6452015-10-02 18:44:03222 dsc = [dsc stringByReplacingOccurrencesOfString:@"offer"
223 withString:@"answer"];
224 RTCSessionDescription *answerDescription =
hjon79858f82016-03-14 05:08:26225 [[RTCSessionDescription alloc] initWithType:RTCSdpTypeAnswer sdp:dsc];
haysc913e6452015-10-02 18:44:03226 ARDSignalingMessage *answer =
227 [[ARDSessionDescriptionMessage alloc]
228 initWithDescription:answerDescription];
229 [self sendMessage:answer];
230 break;
231 }
232 case kARDSignalingMessageTypeAnswer:
233 // Should not receive answer in loopback scenario.
234 break;
235 case kARDSignalingMessageTypeCandidate:
Honghai Zhangda2ba4d2016-05-23 18:53:14236 case kARDSignalingMessageTypeCandidateRemoval:
haysc913e6452015-10-02 18:44:03237 // Send back to server.
238 [self sendMessage:message];
239 break;
240 case kARDSignalingMessageTypeBye:
241 // Nothing to do.
242 return;
243 }
244}
245
246- (void)channel:(id<ARDSignalingChannel>)channel
247 didChangeState:(ARDSignalingChannelState)state {
248}
249
250@end
251