diff --git a/example/lib/src/register.dart b/example/lib/src/register.dart index 62c6de7c..3081c0bb 100644 --- a/example/lib/src/register.dart +++ b/example/lib/src/register.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:sip_ua/sip_ua.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; class RegisterWidget extends StatefulWidget { final SIPUAHelper? _helper; @@ -14,6 +15,7 @@ class RegisterWidget extends StatefulWidget { class _MyRegisterWidget extends State implements SipUaHelperListener { final TextEditingController _passwordController = TextEditingController(); + final TextEditingController _portController = TextEditingController(); final TextEditingController _wsUriController = TextEditingController(); final TextEditingController _sipUriController = TextEditingController(); final TextEditingController _displayNameController = TextEditingController(); @@ -26,6 +28,8 @@ class _MyRegisterWidget extends State late SharedPreferences _preferences; late RegistrationState _registerState; + TransportType _selectedTransport = TransportType.TCP; + SIPUAHelper? get helper => widget._helper; @override @@ -34,6 +38,9 @@ class _MyRegisterWidget extends State _registerState = helper!.registerState; helper!.addSipUaHelperListener(this); _loadSettings(); + if (kIsWeb) { + _selectedTransport = TransportType.WS; + } } @override @@ -56,6 +63,7 @@ class _MyRegisterWidget extends State void _loadSettings() async { _preferences = await SharedPreferences.getInstance(); setState(() { + _portController.text = '5060'; _wsUriController.text = _preferences.getString('ws_uri') ?? 'wss://tryit.jssip.net:10443'; _sipUriController.text = @@ -69,6 +77,7 @@ class _MyRegisterWidget extends State } void _saveSettings() { + _preferences.setString('port', _portController.text); _preferences.setString('ws_uri', _wsUriController.text); _preferences.setString('sip_uri', _sipUriController.text); _preferences.setString('display_name', _displayNameController.text); @@ -113,12 +122,15 @@ class _MyRegisterWidget extends State UaSettings settings = UaSettings(); - settings.webSocketUrl = _wsUriController.text; + settings.port = _portController.text; settings.webSocketSettings.extraHeaders = _wsExtraHeaders; settings.webSocketSettings.allowBadCertificate = true; //settings.webSocketSettings.userAgent = 'Dart/2.8 (dart:io) for OpenSIPS.'; - + settings.tcpSocketSettings.allowBadCertificate = true; + settings.transportType = _selectedTransport; settings.uri = _sipUriController.text; + settings.webSocketUrl = _wsUriController.text; + settings.host = _sipUriController.text.split('@')[1]; settings.authorizationUser = _authorizationUserController.text; settings.password = _passwordController.text; settings.displayName = _displayNameController.text; @@ -143,14 +155,24 @@ class _MyRegisterWidget extends State style: TextStyle(fontSize: 18, color: Colors.black54), ), ), - SizedBox(height: 40), - Text('WebSocket:'), - TextFormField( - controller: _wsUriController, - keyboardType: TextInputType.text, - autocorrect: false, - textAlign: TextAlign.center, - ), + SizedBox(height: 20), + if (_selectedTransport == TransportType.WS) ...[ + Text('WebSocket:'), + TextFormField( + controller: _wsUriController, + keyboardType: TextInputType.text, + autocorrect: false, + textAlign: TextAlign.center, + ), + ], + if (_selectedTransport == TransportType.TCP) ...[ + Text('Port:'), + TextFormField( + controller: _portController, + keyboardType: TextInputType.text, + textAlign: TextAlign.center, + ), + ], SizedBox(height: 20), Text('SIP URI:'), TextFormField( @@ -192,7 +214,29 @@ class _MyRegisterWidget extends State hintText: _displayNameController.text.isEmpty ? '[Empty]' : null, ), ), - const SizedBox(height: 40), + const SizedBox(height: 20), + if (!kIsWeb) ...[ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + RadioMenuButton( + value: TransportType.TCP, + groupValue: _selectedTransport, + onChanged: ((value) => setState(() { + _selectedTransport = value!; + })), + child: Text("TCP")), + RadioMenuButton( + value: TransportType.WS, + groupValue: _selectedTransport, + onChanged: ((value) => setState(() { + _selectedTransport = value!; + })), + child: Text("WS")), + ], + ), + ], + const SizedBox(height: 20), ElevatedButton( child: Text('Register'), onPressed: () => _handleSave(context), diff --git a/lib/sip_ua.dart b/lib/sip_ua.dart index 3be43a90..03d5fc00 100644 --- a/lib/sip_ua.dart +++ b/lib/sip_ua.dart @@ -1,3 +1,4 @@ /// only expose the bare minimum of internals required export 'src/enum_helper.dart'; export 'src/sip_ua_helper.dart'; +export 'src/transport_type.dart'; diff --git a/lib/src/config.dart b/lib/src/config.dart index 6b23ed98..a38804bb 100644 --- a/lib/src/config.dart +++ b/lib/src/config.dart @@ -1,11 +1,12 @@ import 'package:sip_ua/sip_ua.dart'; +import 'package:sip_ua/src/transports/socket_interface.dart'; +import 'package:sip_ua/src/transports/tcp_socket.dart'; import 'constants.dart' as DartSIP_C; import 'constants.dart'; import 'exceptions.dart' as Exceptions; import 'grammar.dart'; import 'logger.dart'; -import 'socket.dart' as Socket; -import 'transports/websocket_interface.dart'; +import 'transports/web_socket.dart'; import 'uri.dart'; import 'utils.dart' as Utils; @@ -43,8 +44,10 @@ class Settings { // Dtmf mode DtmfMode dtmf_mode = DtmfMode.INFO; + TransportType? transportType; + // Connection options. - List? sockets = []; + List? sockets = []; int connection_recovery_max_interval = 30; int connection_recovery_min_interval = 2; @@ -71,16 +74,17 @@ class Checks { Map mandatory = { 'sockets': (Settings src, Settings? dst) { - List? sockets = src.sockets; + List? sockets = src.sockets; + /* Allow defining sockets parameter as: * Socket: socket * List of Socket: [socket1, socket2] * List of Objects: [{socket: socket1, weight:1}, {socket: Socket2, weight:0}] * List of Objects and Socket: [{socket: socket1}, socket2] */ - List copy = []; + List copy = []; if (sockets is List && sockets!.length > 0) { - for (WebSocketInterface socket in sockets) { + for (SIPUASocketInterface socket in sockets) { copy.add(socket); } } else { @@ -105,6 +109,13 @@ class Checks { } else { dst!.uri = parsed; } + }, + 'transport_type': (Settings src, Settings? dst) { + dynamic transportType = src.transportType; + if (src.transportType == null && dst!.transportType == null) { + throw Exceptions.ConfigurationError('transport type', null); + } + dst!.transportType = transportType; } }; Map optional = diff --git a/lib/src/event_manager/event_manager.dart b/lib/src/event_manager/event_manager.dart index aa84e7b0..7fd8a9f6 100644 --- a/lib/src/event_manager/event_manager.dart +++ b/lib/src/event_manager/event_manager.dart @@ -69,7 +69,7 @@ class EventManager { targets.remove(listener); targets.add(listener); } catch (e, s) { - logger.e(e.toString(), error: e, stackTrace: s); + logger.e(e.toString(), e, s); } } @@ -108,7 +108,7 @@ class EventManager { // logger.w("invoking $event on $target"); target(event); } catch (e, s) { - logger.e(e.toString(), error: e, stackTrace: s); + logger.e(e.toString(), e, s); } } } diff --git a/lib/src/event_manager/transport_events.dart b/lib/src/event_manager/transport_events.dart index 1c128662..881a9d2d 100644 --- a/lib/src/event_manager/transport_events.dart +++ b/lib/src/event_manager/transport_events.dart @@ -1,18 +1,19 @@ -import '../transports/websocket_interface.dart'; +import 'package:sip_ua/src/transports/socket_interface.dart'; +import '../transports/web_socket.dart'; import 'events.dart'; class EventSocketConnected extends EventType { EventSocketConnected({this.socket}); - WebSocketInterface? socket; + SIPUASocketInterface? socket; } class EventSocketConnecting extends EventType { EventSocketConnecting({this.socket}); - WebSocketInterface? socket; + SIPUASocketInterface? socket; } class EventSocketDisconnected extends EventType { - EventSocketDisconnected({WebSocketInterface? socket, this.cause}); - WebSocketInterface? socket; + EventSocketDisconnected({SIPUASocketInterface? socket, this.cause}); + SIPUASocketInterface? socket; ErrorCause? cause; } diff --git a/lib/src/logger.dart b/lib/src/logger.dart index a1a107c6..d991b757 100644 --- a/lib/src/logger.dart +++ b/lib/src/logger.dart @@ -130,7 +130,7 @@ class AnsiColor { String call(String msg) { if (color) { - return '$this$msg$ansiDefault'; + return '$msg$ansiDefault'; } else { return msg; } diff --git a/lib/src/registrator.dart b/lib/src/registrator.dart index 843d992c..806bfbf7 100644 --- a/lib/src/registrator.dart +++ b/lib/src/registrator.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:sip_ua/src/socket_transport.dart'; import 'constants.dart' as DartSIP_C; import 'constants.dart'; import 'event_manager/event_manager.dart'; @@ -10,7 +11,6 @@ import 'name_addr_header.dart'; import 'request_sender.dart'; import 'sip_message.dart'; import 'timers.dart'; -import 'transport.dart'; import 'ua.dart'; import 'uri.dart'; import 'utils.dart' as utils; @@ -24,7 +24,7 @@ class UnHandledResponse { } class Registrator { - Registrator(UA ua, [Transport? transport]) { + Registrator(UA ua, [SocketTransport? transport]) { int reg_id = 1; // Force reg_id to 1. _ua = ua; @@ -71,7 +71,7 @@ class Registrator { } late UA _ua; - Transport? _transport; + SocketTransport? _transport; late URI _registrar; int? _expires; String? _call_id; @@ -86,7 +86,7 @@ class Registrator { bool get registered => _registered; - Transport? get transport => _transport; + SocketTransport? get transport => _transport; void setExtraHeaders(List? extraHeaders) { _extraHeaders = extraHeaders ?? []; diff --git a/lib/src/request_sender.dart b/lib/src/request_sender.dart index 210e77b1..1d2f53cc 100644 --- a/lib/src/request_sender.dart +++ b/lib/src/request_sender.dart @@ -59,16 +59,16 @@ class RequestSender { switch (_method) { case SipMethod.INVITE: - clientTransaction = - InviteClientTransaction(_ua, _ua.transport!, _request!, handlers); + clientTransaction = InviteClientTransaction( + _ua, _ua.socketTransport!, _request!, handlers); break; case SipMethod.ACK: - clientTransaction = - AckClientTransaction(_ua, _ua.transport!, _request!, handlers); + clientTransaction = AckClientTransaction( + _ua, _ua.socketTransport!, _request!, handlers); break; default: clientTransaction = NonInviteClientTransaction( - _ua, _ua.transport!, _request!, handlers); + _ua, _ua.socketTransport!, _request!, handlers); } clientTransaction?.send(); diff --git a/lib/src/rtc_session.dart b/lib/src/rtc_session.dart index 0cd11daf..6ec5fa1c 100644 --- a/lib/src/rtc_session.dart +++ b/lib/src/rtc_session.dart @@ -1,8 +1,9 @@ import 'dart:async'; - +import 'dart:convert'; +import 'package:crypto/crypto.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:sdp_transform/sdp_transform.dart' as sdp_transform; - +import 'package:sdp_transform/sdp_transform.dart'; import 'package:sip_ua/sip_ua.dart'; import 'constants.dart' as DartSIP_C; import 'constants.dart'; @@ -692,8 +693,7 @@ class RTCSession extends EventManager implements Owner { if (_status == C.STATUS_TERMINATED) { return; } - logger.e('Failed to answer(): ${error.toString()}', - error: error, stackTrace: s); + logger.e('Failed to answer(): ${error.toString()}', error, s); } } @@ -1951,27 +1951,28 @@ class RTCSession extends EventManager implements Owner { } Future _processInDialogSdpOffer( - dynamic request) async { + IncomingRequest request) async { logger.d('_processInDialogSdpOffer()'); - Map sdp = request.parseSDP(); + Map? sdp = request.parseSDP(); bool hold = false; + if (sdp != null) { + for (Map m in sdp['media']) { + if (holdMediaTypes.indexOf(m['type']) == -1) { + continue; + } - for (Map m in sdp['media']) { - if (holdMediaTypes.indexOf(m['type']) == -1) { - continue; - } - - String direction = m['direction'] ?? sdp['direction'] ?? 'sendrecv'; + String direction = m['direction'] ?? sdp['direction'] ?? 'sendrecv'; - if (direction == 'sendonly' || direction == 'inactive') { - hold = true; - } - // If at least one of the streams is active don't emit 'hold'. - else { - hold = false; - break; + if (direction == 'sendonly' || direction == 'inactive') { + hold = true; + } + // If at least one of the streams is active don't emit 'hold'. + else { + hold = false; + break; + } } } @@ -2294,7 +2295,7 @@ class RTCSession extends EventManager implements Owner { request_sender.send(); } catch (error, s) { - logger.e(error.toString(), error: error, stackTrace: s); + logger.e(error.toString(), error, s); _failed('local', null, null, null, 500, DartSIP_C.CausesType.WEBRTC_ERROR, 'Can\'t create local SDP'); if (_status == C.STATUS_TERMINATED) { @@ -2560,7 +2561,7 @@ class RTCSession extends EventManager implements Owner { 'eventHandlers': handlers }); } catch (e, s) { - logger.e(e.toString(), error: e, stackTrace: s); + logger.e(e.toString(), e, s); onFailed(); } } diff --git a/lib/src/rtc_session/dtmf.dart b/lib/src/rtc_session/dtmf.dart index a5454fae..df8269e3 100644 --- a/lib/src/rtc_session/dtmf.dart +++ b/lib/src/rtc_session/dtmf.dart @@ -51,7 +51,6 @@ class DTMF extends EventManager { throw Exceptions.InvalidStateError(_session.status); } - print(options); List extraHeaders = options['extraHeaders'] != null ? Utils.cloneArray(options['extraHeaders']) : []; diff --git a/lib/src/sanity_check.dart b/lib/src/sanity_check.dart index 09d8cb76..112672f0 100644 --- a/lib/src/sanity_check.dart +++ b/lib/src/sanity_check.dart @@ -4,7 +4,7 @@ import 'logger.dart'; import 'sip_message.dart'; import 'transactions/invite_server.dart'; import 'transactions/non_invite_server.dart'; -import 'transport.dart'; +import 'socket_transport.dart'; import 'ua.dart'; import 'utils.dart' as Utils; @@ -28,9 +28,9 @@ const List responses = [ // local variables. late IncomingMessage message; late UA ua; -late Transport transport; +late SocketTransport transport; -bool sanityCheck(IncomingMessage m, UA u, Transport t) { +bool sanityCheck(IncomingMessage m, UA u, SocketTransport t) { message = m; ua = u; transport = t; diff --git a/lib/src/sip_message.dart b/lib/src/sip_message.dart index e056ba24..e243679d 100644 --- a/lib/src/sip_message.dart +++ b/lib/src/sip_message.dart @@ -10,7 +10,7 @@ import 'exceptions.dart' as Exceptions; import 'grammar.dart'; import 'logger.dart'; import 'name_addr_header.dart'; -import 'transport.dart'; +import 'socket_transport.dart'; import 'ua.dart'; import 'uri.dart'; import 'utils.dart' as utils; @@ -47,7 +47,9 @@ class OutgoingRequest { if (params['route_set'] != null) { setHeader('route', params['route_set']); } else if (ua.configuration.use_preloaded_route) { - setHeader('route', '<${ua.transport!.sip_uri};lr>'); + if (ua.socketTransport != null) { + setHeader('route', '<${ua.socketTransport!.sip_uri};lr>'); + } } // Via. @@ -521,7 +523,7 @@ class IncomingRequest extends IncomingMessage { } UA? ua; URI? ruri; - Transport? transport; + SocketTransport? transport; TransactionBase? server_transaction; /** * Stateful reply. diff --git a/lib/src/sip_ua_helper.dart b/lib/src/sip_ua_helper.dart index 22aec9c1..3bd8feaf 100644 --- a/lib/src/sip_ua_helper.dart +++ b/lib/src/sip_ua_helper.dart @@ -2,8 +2,11 @@ import 'dart:async'; import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:logger/logger.dart'; +import 'package:sip_ua/sip_ua.dart'; import 'package:sip_ua/src/map_helper.dart'; +import 'package:sip_ua/src/transports/socket_interface.dart'; +import 'package:sip_ua/src/transports/tcp_socket.dart'; import 'config.dart'; import 'constants.dart' as DartSIP_C; import 'event_manager/event_manager.dart'; @@ -15,7 +18,7 @@ import 'rtc_session/refer_subscriber.dart'; import 'sip_message.dart'; import 'stack_trace_nj.dart'; import 'subscriber.dart'; -import 'transports/websocket_interface.dart'; +import 'transports/web_socket.dart'; import 'ua.dart'; class SIPUAHelper extends EventManager { @@ -51,9 +54,11 @@ class SIPUAHelper extends EventManager { } bool get connecting { - if (_ua != null && _ua!.transport != null) { - return _ua!.transport!.isConnecting(); - } + if (_ua == null) return false; + + if (_ua!.socketTransport != null) + return _ua!.socketTransport!.isConnecting(); + return false; } @@ -100,8 +105,7 @@ class SIPUAHelper extends EventManager { _ua!.call(target, options); return true; } else { - logger.e('Not connected, you will need to register.', - stackTrace: StackTraceNJ()); + logger.e('Not connected, you will need to register.', StackTraceNJ()); } return false; } @@ -120,10 +124,25 @@ class SIPUAHelper extends EventManager { // Reset settings _settings = Settings(); - WebSocketInterface socket = WebSocketInterface(uaSettings.webSocketUrl, - messageDelay: _settings.sip_message_delay, - webSocketSettings: uaSettings.webSocketSettings); - _settings.sockets = [socket]; + + _settings.sockets = []; + + if (uaSettings.transportType == TransportType.TCP) { + SIPUATcpSocket socket = SIPUATcpSocket( + uaSettings.host ?? '0.0.0.0', uaSettings.port ?? '5060', + messageDelay: 1); + _settings.sockets!.add(socket); + } + + if (uaSettings.transportType == TransportType.WS) { + SIPUAWebSocket socket = SIPUAWebSocket( + uaSettings.webSocketUrl ?? 'wss://tryit.jssip.net:10443', + messageDelay: _settings.sip_message_delay, + webSocketSettings: uaSettings.webSocketSettings); + _settings.sockets!.add(socket); + } + + _settings.transportType = uaSettings.transportType!; _settings.uri = uaSettings.uri; _settings.sip_message_delay = uaSettings.sip_message_delay; _settings.realm = uaSettings.realm; @@ -213,7 +232,7 @@ class SIPUAHelper extends EventManager { _ua!.start(); } catch (e, s) { - logger.e(e.toString(), error: e, stackTrace: s); + logger.e(e.toString(), e, s); } } @@ -684,14 +703,26 @@ class WebSocketSettings { String? transport_scheme; } +class TcpSocketSettings { + /// Add additional HTTP headers, such as:'Origin','Host' or others + Map extraHeaders = {}; + + /// `User Agent` field for dart http client. + String? userAgent; + + /// Don‘t check the server certificate + /// for self-signed certificate. + bool allowBadCertificate = false; +} + enum DtmfMode { INFO, RFC2833, } class UaSettings { - late String webSocketUrl; WebSocketSettings webSocketSettings = WebSocketSettings(); + TcpSocketSettings tcpSocketSettings = TcpSocketSettings(); /// May not need to register if on a static IP, just Auth /// Default is true @@ -705,7 +736,10 @@ class UaSettings { /// `User Agent` field for sip message. String? userAgent; + String? host; + String? port; String? uri; + String? webSocketUrl; String? realm; String? authorizationUser; String? password; @@ -714,6 +748,8 @@ class UaSettings { String? instanceId; String? registrarServer; + TransportType? transportType; + /// DTMF mode, in band (rfc2833) or out of band (sip info) DtmfMode dtmfMode = DtmfMode.INFO; diff --git a/lib/src/socket.dart b/lib/src/socket.dart deleted file mode 100644 index dd342928..00000000 --- a/lib/src/socket.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'grammar.dart'; -import 'logger.dart'; -import 'transports/websocket_interface.dart'; -import 'utils.dart' as Utils; - -/// Socket Interface. -abstract class Socket { - late String via_transport; - String? get url; - String? get sip_uri; - - void connect(); - void disconnect(); - void send(dynamic data); - - void Function()? onconnect; - void Function(WebSocketInterface socket, bool error, int? closeCode, - String? reason)? ondisconnect; - void Function(dynamic data)? ondata; -} diff --git a/lib/src/transport.dart b/lib/src/socket_transport.dart similarity index 80% rename from lib/src/transport.dart rename to lib/src/socket_transport.dart index a93f3b0f..b6321723 100644 --- a/lib/src/transport.dart +++ b/lib/src/socket_transport.dart @@ -2,67 +2,49 @@ import 'dart:async'; import 'dart:math'; import 'package:sip_ua/src/event_manager/events.dart'; +import 'package:sip_ua/src/transport_constants.dart'; +import 'package:sip_ua/src/transports/socket_interface.dart'; +import 'package:sip_ua/src/transports/tcp_socket.dart'; import 'exceptions.dart' as Exceptions; import 'logger.dart'; -import 'socket.dart' as Socket; import 'stack_trace_nj.dart'; import 'timers.dart'; -import 'transports/websocket_interface.dart'; +import 'transports/web_socket.dart'; import 'utils.dart'; -/** - * Constants - */ -class C { - // Transport status. - static const int STATUS_CONNECTED = 0; - static const int STATUS_CONNECTING = 1; - static const int STATUS_DISCONNECTED = 2; - - // Socket status. - static const int SOCKET_STATUS_READY = 0; - static const int SOCKET_STATUS_ERROR = 1; - - // Recovery options. - static const Map recovery_options = { - 'min_interval': 2, // minimum interval in seconds between recover attempts - 'max_interval': 30 // maximum interval in seconds between recover attempts - }; -} - /* * Manages one or multiple DartSIP.Socket instances. * Is reponsible for transport recovery logic among all socket instances. * * @socket DartSIP::Socket instance */ -class Transport { - Transport(List sockets, +class SocketTransport { + SocketTransport(List? sockets, [Map recovery_options = C.recovery_options]) { - logger.d('new()'); + logger.d('Socket Transport new()'); _recovery_options = recovery_options; // We must recieve at least 1 socket - if (sockets.length == 0) { - throw Exceptions.TypeError('invalid argument: sockets'); + if (sockets!.length == 0) { + throw Exceptions.TypeError( + 'invalid argument: Must recieve atleast 1 web socket'); } - for (WebSocketInterface socket in sockets) { + for (SIPUASocketInterface socket in sockets) { _socketsMap.add({ 'socket': socket, 'weight': socket.weight ?? 0, 'status': C.SOCKET_STATUS_READY }); } - // Get the socket with higher weight. _getSocket(); } int status = C.STATUS_DISCONNECTED; // Current socket. - late WebSocketInterface socket; + late SIPUASocketInterface socket; // Socket collection. final List> _socketsMap = >[]; late Map _recovery_options; @@ -70,10 +52,11 @@ class Transport { Timer? _recovery_timer; bool _close_requested = false; - late void Function(WebSocketInterface? socket, int? attempts) onconnecting; - late void Function(WebSocketInterface? socket, ErrorCause cause) ondisconnect; - late void Function(Transport transport) onconnect; - late void Function(Transport transport, String messageData) ondata; + late void Function(SIPUASocketInterface? socket, int? attempts) onconnecting; + late void Function(SIPUASocketInterface? socket, ErrorCause cause) + ondisconnect; + late void Function(SocketTransport transport) onconnect; + late void Function(SocketTransport transport, String messageData) ondata; /** * Instance Methods @@ -86,7 +69,7 @@ class Transport { String? get sip_uri => socket.sip_uri; void connect() { - logger.d('connect()'); + logger.d('Transport connect()'); if (isConnected()) { logger.d('Transport is already connected'); @@ -113,7 +96,7 @@ class Transport { } void disconnect() { - logger.d('close()'); + logger.d('Transport close()'); _close_requested = true; _recover_attempts = 0; @@ -127,7 +110,7 @@ class Transport { // Unbind socket event callbacks. socket.onconnect = () => () {}; - socket.ondisconnect = (WebSocketInterface socket, bool error, + socket.ondisconnect = (SIPUASocketInterface socket, bool error, int? closeCode, String? reason) => () {}; socket.ondata = (dynamic data) => () {}; @@ -142,18 +125,18 @@ class Transport { } bool send(dynamic data) { - logger.d('send()'); + logger.d('Socket Transport send()'); if (!isConnected()) { logger.e( 'unable to send message, transport is not connected. Current state is $status', - error: e, - stackTrace: StackTraceNJ()); + null, + StackTraceNJ()); + return false; } - String message = data.toString(); - //logger.d('sending message:\n\n$message\n'); + message.split('fingerprint'); return socket.send(message); } @@ -249,7 +232,7 @@ class Transport { } void _onDisconnect( - WebSocketInterface socket, bool error, int? closeCode, String? reason) { + SIPUASocketInterface socket, bool error, int? closeCode, String? reason) { status = C.STATUS_DISCONNECTED; ondisconnect( socket, @@ -275,8 +258,10 @@ class Transport { // CRLF Keep Alive response from server. Ignore it. if (data == '\r\n') { logger.d('received message with CRLF Keep Alive response'); + return; } + // Binary message. else if (data is! String) { try { @@ -287,7 +272,6 @@ class Transport { ' message discarded'); return; } - logger.d('received binary message:\n\n$data\n'); } diff --git a/lib/src/transactions/ack_client.dart b/lib/src/transactions/ack_client.dart index 59401890..e57b39aa 100644 --- a/lib/src/transactions/ack_client.dart +++ b/lib/src/transactions/ack_client.dart @@ -2,14 +2,14 @@ import 'package:sip_ua/src/sip_message.dart'; import '../event_manager/event_manager.dart'; import '../event_manager/internal_events.dart'; import '../logger.dart'; -import '../transport.dart'; +import '../socket_transport.dart'; import '../ua.dart'; import '../utils.dart'; import 'transaction_base.dart'; class AckClientTransaction extends TransactionBase { - AckClientTransaction(UA ua, Transport transport, OutgoingRequest request, - EventManager eventHandlers) { + AckClientTransaction(UA ua, SocketTransport transport, + OutgoingRequest request, EventManager eventHandlers) { id = 'z9hG4bK${(Math.random() * 10000000).floor()}'; this.transport = transport; this.request = request; diff --git a/lib/src/transactions/invite_client.dart b/lib/src/transactions/invite_client.dart index aafc80d9..7ee4d86e 100644 --- a/lib/src/transactions/invite_client.dart +++ b/lib/src/transactions/invite_client.dart @@ -6,14 +6,14 @@ import '../event_manager/internal_events.dart'; import '../logger.dart'; import '../sip_message.dart'; import '../timers.dart'; -import '../transport.dart'; +import '../socket_transport.dart'; import '../ua.dart'; import '../utils.dart'; import 'transaction_base.dart'; class InviteClientTransaction extends TransactionBase { - InviteClientTransaction(UA ua, Transport transport, OutgoingRequest request, - EventManager eventHandlers) { + InviteClientTransaction(UA ua, SocketTransport transport, + OutgoingRequest request, EventManager eventHandlers) { id = 'z9hG4bK${(Math.random() * 10000000).floor()}'; this.ua = ua; this.transport = transport; diff --git a/lib/src/transactions/invite_server.dart b/lib/src/transactions/invite_server.dart index 8fdf65f0..6e92538c 100644 --- a/lib/src/transactions/invite_server.dart +++ b/lib/src/transactions/invite_server.dart @@ -4,13 +4,13 @@ import '../event_manager/internal_events.dart'; import '../logger.dart'; import '../sip_message.dart'; import '../timers.dart'; -import '../transport.dart'; +import '../socket_transport.dart'; import '../ua.dart'; import 'transaction_base.dart'; class InviteServerTransaction extends TransactionBase { InviteServerTransaction( - UA ua, Transport? transport, IncomingRequest request) { + UA ua, SocketTransport? transport, IncomingRequest request) { id = request.via_branch; this.ua = ua; this.transport = transport; diff --git a/lib/src/transactions/non_invite_client.dart b/lib/src/transactions/non_invite_client.dart index 0ec01a45..3b2ba5fc 100644 --- a/lib/src/transactions/non_invite_client.dart +++ b/lib/src/transactions/non_invite_client.dart @@ -5,13 +5,13 @@ import '../event_manager/internal_events.dart'; import '../logger.dart'; import '../sip_message.dart'; import '../timers.dart'; -import '../transport.dart'; +import '../socket_transport.dart'; import '../ua.dart'; import '../utils.dart'; import 'transaction_base.dart'; class NonInviteClientTransaction extends TransactionBase { - NonInviteClientTransaction(UA ua, Transport transport, + NonInviteClientTransaction(UA ua, SocketTransport transport, OutgoingRequest request, EventManager eventHandlers) { id = 'z9hG4bK${Math.random().floor()}'; this.ua = ua; diff --git a/lib/src/transactions/non_invite_server.dart b/lib/src/transactions/non_invite_server.dart index 3860cec6..fffc25a9 100644 --- a/lib/src/transactions/non_invite_server.dart +++ b/lib/src/transactions/non_invite_server.dart @@ -4,13 +4,13 @@ import 'package:sip_ua/src/sip_message.dart'; import '../event_manager/internal_events.dart'; import '../logger.dart'; import '../timers.dart'; -import '../transport.dart'; +import '../socket_transport.dart'; import '../ua.dart'; import 'transaction_base.dart'; class NonInviteServerTransaction extends TransactionBase { NonInviteServerTransaction( - UA ua, Transport? transport, IncomingRequest request) { + UA ua, SocketTransport? transport, IncomingRequest request) { id = request.via_branch; this.ua = ua; this.transport = transport; diff --git a/lib/src/transactions/transaction_base.dart b/lib/src/transactions/transaction_base.dart index f3da869d..38940087 100644 --- a/lib/src/transactions/transaction_base.dart +++ b/lib/src/transactions/transaction_base.dart @@ -1,6 +1,6 @@ import '../event_manager/event_manager.dart'; import '../sip_message.dart'; -import '../transport.dart'; +import '../socket_transport.dart'; import '../ua.dart'; enum TransactionState { @@ -17,7 +17,7 @@ enum TransactionState { abstract class TransactionBase extends EventManager { String? id; late UA ua; - Transport? transport; + SocketTransport? transport; TransactionState? state; IncomingMessage? last_response; dynamic request; diff --git a/lib/src/transport_constants.dart b/lib/src/transport_constants.dart new file mode 100644 index 00000000..a2d84e5c --- /dev/null +++ b/lib/src/transport_constants.dart @@ -0,0 +1,19 @@ +/** + * Constants + */ +class C { + // Transport status. + static const int STATUS_CONNECTED = 0; + static const int STATUS_CONNECTING = 1; + static const int STATUS_DISCONNECTED = 2; + + // Socket status. + static const int SOCKET_STATUS_READY = 0; + static const int SOCKET_STATUS_ERROR = 1; + + // Recovery options. + static const Map recovery_options = { + 'min_interval': 2, // minimum interval in seconds between recover attempts + 'max_interval': 30 // maximum interval in seconds between recover attempts + }; +} diff --git a/lib/src/transport_type.dart b/lib/src/transport_type.dart new file mode 100644 index 00000000..54cabf36 --- /dev/null +++ b/lib/src/transport_type.dart @@ -0,0 +1 @@ +enum TransportType { TCP, WS } diff --git a/lib/src/transports/socket_interface.dart b/lib/src/transports/socket_interface.dart new file mode 100644 index 00000000..aa74c2c6 --- /dev/null +++ b/lib/src/transports/socket_interface.dart @@ -0,0 +1,18 @@ +abstract class SIPUASocketInterface { + String? get url; + String? get sip_uri; + String get via_transport; + int? get weight; + set via_transport(String value); + + void Function()? onconnect; + void Function(SIPUASocketInterface socket, bool error, int? closeCode, + String? reason)? ondisconnect; + void Function(dynamic data)? ondata; + + void connect(); + void disconnect(); + bool send(dynamic message); + bool isConnected(); + bool isConnecting(); +} diff --git a/lib/src/transports/tcp_socket.dart b/lib/src/transports/tcp_socket.dart new file mode 100644 index 00000000..1820edf5 --- /dev/null +++ b/lib/src/transports/tcp_socket.dart @@ -0,0 +1,179 @@ +import 'package:sip_ua/sip_ua.dart'; +import 'package:sip_ua/src/transports/socket_interface.dart'; +import 'package:sip_ua/src/transports/tcp_socket_impl.dart'; +import '../grammar.dart'; +import '../logger.dart'; + +import 'websocket_dart_impl.dart' + if (dart.library.js) 'websocket_web_impl.dart'; + +class SIPUATcpSocket extends SIPUASocketInterface { + SIPUATcpSocket(String host, String port, + {required int messageDelay, + TcpSocketSettings? tcpSocketSettings, + int? weight}) + : _messageDelay = messageDelay { + logger.d('new() [host:$host:$port]'); + String transport_scheme = 'tcp'; + _weight = weight; + _host = host; + _port = port; + + _sip_uri = 'sip:$host:$port;transport=$transport_scheme'; + logger.d('TCPC SIP URI: $_sip_uri'); + _via_transport = transport_scheme.toUpperCase(); + _tcpSocketSettings = tcpSocketSettings ?? TcpSocketSettings(); + } + + final int _messageDelay; + + String? _host; + String? _port; + String? _sip_uri; + late String _via_transport; + final String _tcp_socket_protocol = 'sip'; + SIPUATcpSocketImpl? _tcpSocketImpl; + bool _closed = false; + bool _connected = false; + int? _weight; + int? status; + late TcpSocketSettings _tcpSocketSettings; + + @override + String get via_transport => _via_transport; + + @override + set via_transport(String value) { + _via_transport = value.toUpperCase(); + } + + @override + int? get weight => _weight; + + @override + String? get sip_uri => _sip_uri; + + String? get host => _host; + + String? get port => _port; + + @override + void connect() async { + logger.d('connect()'); + + if (_host == null) { + throw AssertionError('Invalid argument: _host'); + } + if (_port == null) { + throw AssertionError('Invalid argument: _port'); + } + + if (_tcpSocketImpl != null) { + disconnect(); + } + logger.d('connecting to TcpSocket $_host:$_port'); + try { + _tcpSocketImpl = SIPUATcpSocketImpl( + _messageDelay, _host ?? '0.0.0.0', _port ?? '5060'); + + _tcpSocketImpl!.onOpen = () { + _closed = false; + _connected = true; + logger.d('Tcp Socket is now connected?'); + _onOpen(); + }; + + _tcpSocketImpl!.onData = (dynamic data) { + _onMessage(data); + }; + + _tcpSocketImpl!.onClose = (int? closeCode, String? closeReason) { + logger.d('Closed [$closeCode, $closeReason]!'); + _connected = false; + _onClose(true, closeCode, closeReason); + }; + + _tcpSocketImpl!.connect( + protocols: [_tcp_socket_protocol], + tcpSocketSettings: _tcpSocketSettings); + } catch (e, s) { + logger.e(e.toString(), null, s); + _connected = false; + logger.e('TcpSocket error: $e'); + } + } + + @override + void disconnect() { + logger.d('disconnect()'); + if (_closed) return; + // Don't wait for the WebSocket 'close' event, do it now. + _closed = true; + _connected = false; + _onClose(true, 0, 'Client send disconnect'); + try { + if (_tcpSocketImpl != null) { + _tcpSocketImpl!.close(); + } + } catch (error) { + logger.e('close() | error closing the TcpSocket: $error'); + } + } + + @override + bool send(dynamic message) { + logger.d('send()'); + if (_closed) { + throw 'transport closed'; + } + try { + _tcpSocketImpl!.send(message); + return true; + } catch (error) { + logger.e('send() | error sending message: $error'); + throw error; + } + } + + @override + bool isConnected() { + return _connected; + } + + /** + * TcpSocket Event Handlers + */ + void _onOpen() { + logger.d('TcpSocket $_host:$port connected'); + onconnect!(); + } + + void _onClose(bool wasClean, int? code, String? reason) { + logger.d('TcpSocket $_host:$port closed'); + if (wasClean == false) { + logger.d('TcpSocket abrupt disconnection'); + } + ondisconnect!(this, !wasClean, code, reason); + } + + void _onMessage(dynamic data) { + logger.d('Received TcpSocket data'); + if (data != null) { + if (data.toString().trim().length > 0) { + ondata!(data); + } else { + logger.d('Received and ignored empty packet'); + } + } + } + + @override + bool isConnecting() { + // TODO: implement isConnecting + throw UnimplementedError(); + } + + @override + // TODO: implement url + String? get url => throw UnimplementedError(); +} diff --git a/lib/src/transports/tcp_socket_impl.dart b/lib/src/transports/tcp_socket_impl.dart new file mode 100644 index 00000000..d3e1de2e --- /dev/null +++ b/lib/src/transports/tcp_socket_impl.dart @@ -0,0 +1,75 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:math'; + +import 'package:sip_ua/src/sip_ua_helper.dart'; +import '../logger.dart'; + +typedef OnMessageCallback = void Function(dynamic msg); +typedef OnCloseCallback = void Function(int? code, String? reason); +typedef OnOpenCallback = void Function(); + +class SIPUATcpSocketImpl { + SIPUATcpSocketImpl(this.messageDelay, this._host, this._port); + + final String _host; + final String _port; + + Socket? _socket; + OnOpenCallback? onOpen; + OnMessageCallback? onData; + OnCloseCallback? onClose; + final int messageDelay; + + void connect( + {Iterable? protocols, + required TcpSocketSettings tcpSocketSettings}) async { + handleQueue(); + logger.i('connect $_host:$_port'); + try { + if (tcpSocketSettings.allowBadCertificate) { + // /// Allow self-signed certificate, for test only. + // _socket = await _connectForBadCertificate(_url, tcpSocketSettings); + } else { + // used to have these + //protocols: protocols, headers: webSocketSettings.extraHeaders + _socket = await Socket.connect( + _host, + int.parse(_port), + ); + } + + onOpen?.call(); + + _socket!.listen((dynamic data) { + onData?.call(data); + }, onDone: () { + // onClose?.call(_socket!., _socket!.closeReason); + }); + } catch (e) { + onClose?.call(500, e.toString()); + } + } + + final StreamController queue = StreamController.broadcast(); + void handleQueue() async { + queue.stream.asyncMap((dynamic event) async { + await Future.delayed(Duration(milliseconds: messageDelay)); + return event; + }).listen((dynamic event) async { + _socket!.add(event.codeUnits); + logger.d('send: \n\n$event'); + }); + } + + void send(dynamic data) async { + if (_socket != null) { + queue.add(data); + } + } + + void close() { + _socket!.close(); + } +} diff --git a/lib/src/transports/websocket_interface.dart b/lib/src/transports/web_socket.dart similarity index 89% rename from lib/src/transports/websocket_interface.dart rename to lib/src/transports/web_socket.dart index a7c11a23..9fd511ff 100644 --- a/lib/src/transports/websocket_interface.dart +++ b/lib/src/transports/web_socket.dart @@ -1,17 +1,20 @@ import 'package:sip_ua/sip_ua.dart'; +import 'package:sip_ua/src/transports/socket_interface.dart'; import '../grammar.dart'; import '../logger.dart'; -import '../socket.dart'; import 'websocket_dart_impl.dart' if (dart.library.js) 'websocket_web_impl.dart'; -class WebSocketInterface implements Socket { - WebSocketInterface(String url, - {required int messageDelay, WebSocketSettings? webSocketSettings}) +class SIPUAWebSocket extends SIPUASocketInterface { + SIPUAWebSocket(String url, + {required int messageDelay, + WebSocketSettings? webSocketSettings, + int? weight}) : _messageDelay = messageDelay { logger.d('new() [url:$url]'); _url = url; + _weight = weight; dynamic parsed_url = Grammar.parse(url, 'absoluteURI'); if (parsed_url == -1) { logger.e('invalid WebSocket URI: $url'); @@ -38,20 +41,13 @@ class WebSocketInterface implements Socket { String? _sip_uri; late String _via_transport; final String _websocket_protocol = 'sip'; - WebSocketImpl? _ws; + SIPUAWebSocketImpl? _ws; bool _closed = false; bool _connected = false; - int? weight; + int? _weight; int? status; late WebSocketSettings _webSocketSettings; - @override - void Function()? onconnect; - @override - void Function(WebSocketInterface socket, bool error, int? closeCode, - String? reason)? ondisconnect; - @override - void Function(dynamic data)? ondata; @override String get via_transport => _via_transport; @@ -63,6 +59,9 @@ class WebSocketInterface implements Socket { @override String? get sip_uri => _sip_uri; + @override + int? get weight => _weight; + @override String? get url => _url; @@ -86,7 +85,7 @@ class WebSocketInterface implements Socket { } logger.d('connecting to WebSocket $_url'); try { - _ws = WebSocketImpl(_url!, _messageDelay); + _ws = SIPUAWebSocketImpl(_url!, _messageDelay); _ws!.onOpen = () { _closed = false; @@ -109,7 +108,7 @@ class WebSocketInterface implements Socket { protocols: [_websocket_protocol], webSocketSettings: _webSocketSettings); } catch (e, s) { - logger.e(e.toString(), error: e, stackTrace: s); + logger.e(e.toString(), e, s); _connected = false; logger.e('WebSocket $_url error: $e'); } @@ -147,10 +146,12 @@ class WebSocketInterface implements Socket { } } + @override bool isConnected() { return _connected; } + @override bool isConnecting() { return _ws != null && _ws!.isConnecting(); } diff --git a/lib/src/transports/websocket_dart_impl.dart b/lib/src/transports/websocket_dart_impl.dart index 5986aad4..6516515c 100644 --- a/lib/src/transports/websocket_dart_impl.dart +++ b/lib/src/transports/websocket_dart_impl.dart @@ -10,8 +10,8 @@ typedef OnMessageCallback = void Function(dynamic msg); typedef OnCloseCallback = void Function(int? code, String? reason); typedef OnOpenCallback = void Function(); -class WebSocketImpl { - WebSocketImpl(this._url, this.messageDelay); +class SIPUAWebSocketImpl { + SIPUAWebSocketImpl(this._url, this.messageDelay); final String _url; WebSocket? _socket; @@ -62,7 +62,7 @@ class WebSocketImpl { } void close() { - _socket!.close(); + if (_socket != null) _socket!.close(); } bool isConnecting() { diff --git a/lib/src/transports/websocket_web_impl.dart b/lib/src/transports/websocket_web_impl.dart index a9692581..f72ebe11 100644 --- a/lib/src/transports/websocket_web_impl.dart +++ b/lib/src/transports/websocket_web_impl.dart @@ -8,8 +8,8 @@ typedef OnMessageCallback = void Function(dynamic msg); typedef OnCloseCallback = void Function(int? code, String? reason); typedef OnOpenCallback = void Function(); -class WebSocketImpl { - WebSocketImpl(this._url, this.messageDelay); +class SIPUAWebSocketImpl { + SIPUAWebSocketImpl(this._url, this.messageDelay); final String _url; WebSocket? _socket; diff --git a/lib/src/ua.dart b/lib/src/ua.dart index ad467116..20a932dc 100644 --- a/lib/src/ua.dart +++ b/lib/src/ua.dart @@ -1,5 +1,7 @@ import 'dart:async'; +import 'package:sip_ua/src/transport_type.dart'; +import 'package:sip_ua/src/transports/socket_interface.dart'; import 'config.dart' as config; import 'config.dart'; import 'constants.dart' as DartSIP_C; @@ -17,6 +19,7 @@ import 'registrator.dart'; import 'rtc_session.dart'; import 'sanity_check.dart'; import 'sip_message.dart'; +import 'socket_transport.dart'; import 'subscriber.dart'; import 'timers.dart'; import 'transactions/invite_client.dart'; @@ -25,8 +28,7 @@ import 'transactions/non_invite_client.dart'; import 'transactions/non_invite_server.dart'; import 'transactions/transaction_base.dart'; import 'transactions/transactions.dart'; -import 'transport.dart'; -import 'transports/websocket_interface.dart'; +import 'transports/web_socket.dart'; import 'uri.dart'; import 'utils.dart' as Utils; @@ -114,11 +116,11 @@ class UA extends EventManager { final Set _applicants = {}; final Map _sessions = {}; - Transport? _transport; + SocketTransport? _socketTransport; Contact? _contact; int _status = C.STATUS_INIT; int? _error; - final TransactionBag _transactions = TransactionBag(); + late TransactionBag _transactions; // Custom UA empty object for high level use. final Map _data = {}; @@ -132,7 +134,7 @@ class UA extends EventManager { Settings get configuration => _configuration; - Transport? get transport => _transport; + SocketTransport? get socketTransport => _socketTransport; TransactionBag get transactions => _transactions; @@ -150,8 +152,10 @@ class UA extends EventManager { void start() { logger.d('start()'); + _transactions = TransactionBag(); + if (_status == C.STATUS_INIT) { - _transport!.connect(); + _socketTransport!.connect(); } else if (_status == C.STATUS_USER_CLOSED) { logger.d('restarting UA'); @@ -159,12 +163,12 @@ class UA extends EventManager { if (_closeTimer != null) { clearTimeout(_closeTimer); _closeTimer = null; - _transport!.disconnect(); + _socketTransport!.disconnect(); } // Reconnect. _status = C.STATUS_INIT; - _transport!.connect(); + _socketTransport!.connect(); } else if (_status == C.STATUS_READY) { logger.d('UA is in READY status, not restarted'); } else { @@ -232,7 +236,7 @@ class UA extends EventManager { * Connection state. */ bool isConnected() { - return _transport!.isConnected(); + return _socketTransport!.isConnected(); } /** @@ -331,7 +335,7 @@ class UA extends EventManager { rtcSession.terminate(); } } catch (e, s) { - logger.e(e.toString(), error: e, stackTrace: s); + logger.e(e.toString(), e, s); } } }); @@ -344,7 +348,7 @@ class UA extends EventManager { Subscriber subscriber = _subscribers[key]!; subscriber.terminate(null); } catch (e, s) { - logger.e(e.toString(), error: e, stackTrace: s); + logger.e(e.toString(), e, s); } } }); @@ -362,12 +366,12 @@ class UA extends EventManager { int num_transactions = _transactions.countTransactions(); if (num_transactions == 0 && num_sessions == 0) { - _transport!.disconnect(); + _socketTransport!.disconnect(); } else { _closeTimer = setTimeout(() { logger.i('Closing connection'); _closeTimer = null; - _transport!.disconnect(); + _socketTransport!.disconnect(); }, 2000); } } @@ -619,11 +623,11 @@ class UA extends EventManager { // Create the server transaction. if (method == SipMethod.INVITE) { /* eslint-disable no-*/ - InviteServerTransaction(this, _transport, request); + InviteServerTransaction(this, _socketTransport, request); /* eslint-enable no-*/ } else if (method != SipMethod.ACK && method != SipMethod.CANCEL) { /* eslint-disable no-*/ - NonInviteServerTransaction(this, _transport, request); + NonInviteServerTransaction(this, _socketTransport, request); /* eslint-enable no-*/ } @@ -835,30 +839,25 @@ class UA extends EventManager { .toString() .replaceAll(RegExp(r'sip:', caseSensitive: false), ''); - // Transport. + // Websockets Transport + try { - _transport = Transport(_configuration.sockets!, { + _socketTransport = SocketTransport(_configuration.sockets!, { // Recovery options. 'max_interval': _configuration.connection_recovery_max_interval, 'min_interval': _configuration.connection_recovery_min_interval }); // Transport event callbacks. - _transport!.onconnecting = onTransportConnecting; - _transport!.onconnect = onTransportConnect; - _transport!.ondisconnect = onTransportDisconnect; - _transport!.ondata = onTransportData; + _socketTransport!.onconnecting = onTransportConnecting; + _socketTransport!.onconnect = onTransportConnect; + _socketTransport!.ondisconnect = onTransportDisconnect; + _socketTransport!.ondata = onTransportData; } catch (e) { logger.e('Failed to _loadConfig: ${e.toString()}'); throw Exceptions.ConfigurationError('sockets', _configuration.sockets); } - String transport = 'ws'; - - if (_configuration.sockets!.isNotEmpty) { - transport = _configuration.sockets!.first.via_transport.toLowerCase(); - } - // Remove sockets instance from configuration object. // TODO(cloudwebrtc): need dispose?? _configuration.sockets = null; @@ -880,6 +879,8 @@ class UA extends EventManager { // User no_answer_timeout. _configuration.no_answer_timeout *= 1000; + String transport = _configuration.transportType?.name ?? 'WS'; + // Via Host. if (_configuration.contact_uri != null) { _configuration.via_host = _configuration.contact_uri.host; @@ -902,13 +903,13 @@ class UA extends EventManager { */ // Transport connecting event. - void onTransportConnecting(WebSocketInterface? socket, int? attempts) { + void onTransportConnecting(SIPUASocketInterface? socket, int? attempts) { logger.d('Transport connecting'); emit(EventSocketConnecting(socket: socket)); } // Transport connected event. - void onTransportConnect(Transport transport) { + void onTransportConnect(SocketTransport transport) { logger.d('Transport connected'); if (_status == C.STATUS_USER_CLOSED) { return; @@ -924,7 +925,7 @@ class UA extends EventManager { } // Transport disconnected event. - void onTransportDisconnect(WebSocketInterface? socket, ErrorCause cause) { + void onTransportDisconnect(SIPUASocketInterface? socket, ErrorCause cause) { // Run _onTransportError_ callback on every client transaction using _transport_. _transactions.removeAll().forEach((TransactionBase transaction) { transaction.onTransportError(); @@ -942,7 +943,7 @@ class UA extends EventManager { } // Transport data event. - void onTransportData(Transport transport, String messageData) { + void onTransportData(SocketTransport transport, String messageData) { IncomingMessage? message = Parser.parseMessage(messageData, this); if (message == null) { diff --git a/test/test_sip_ua.dart b/test/test_sip_ua.dart index eaa72871..17af0e99 100644 --- a/test/test_sip_ua.dart +++ b/test/test_sip_ua.dart @@ -2,7 +2,8 @@ import 'dart:async'; import 'package:sip_ua/src/config.dart' as config; import 'package:sip_ua/src/event_manager/event_manager.dart'; -import 'package:sip_ua/src/transports/websocket_interface.dart'; +import 'package:sip_ua/src/transports/socket_interface.dart'; +import 'package:sip_ua/src/transports/web_socket.dart'; import 'package:sip_ua/src/ua.dart'; import 'package:test/test.dart'; @@ -11,8 +12,8 @@ void main() { test(' WebSocket: EchoTest', () async { Completer completer = Completer(); config.Settings configuration = config.Settings(); - configuration.sockets = [ - WebSocketInterface('ws://127.0.0.1:5070/sip', messageDelay: 0) + configuration.sockets = [ + SIPUAWebSocket('ws://127.0.0.1:5070/sip', messageDelay: 0) ]; configuration.authorization_user = '100'; configuration.password = '100'; diff --git a/test/test_websocket.dart b/test/test_websocket.dart index 2d733aaf..81ac1d59 100644 --- a/test/test_websocket.dart +++ b/test/test_websocket.dart @@ -2,8 +2,9 @@ import 'dart:async'; import 'dart:io'; import 'package:sip_ua/src/event_manager/events.dart'; -import 'package:sip_ua/src/transport.dart'; -import 'package:sip_ua/src/transports/websocket_interface.dart'; +import 'package:sip_ua/src/socket_transport.dart'; +import 'package:sip_ua/src/transports/socket_interface.dart'; +import 'package:sip_ua/src/transports/web_socket.dart'; import 'package:test/test.dart'; List testFunctions = [ @@ -28,8 +29,8 @@ List testFunctions = [ } }); - WebSocketInterface client = - WebSocketInterface('ws://127.0.0.1:4040/sip', messageDelay: 0); + SIPUAWebSocket client = + SIPUAWebSocket('ws://127.0.0.1:4040/sip', messageDelay: 0); expect(client.url, 'ws://127.0.0.1:4040/sip'); expect(client.via_transport, 'WS'); @@ -47,7 +48,7 @@ List testFunctions = [ client.disconnect(); completer.complete(); }; - client.ondisconnect = (WebSocketInterface socket, bool error, + client.ondisconnect = (SIPUASocketInterface socket, bool error, int? closeCode, String? reason) { print( 'ondisconnect => error $error [$closeCode] ${reason.toString()}'); @@ -76,26 +77,27 @@ List testFunctions = [ print(' An error occurred. $error'); } }); - WebSocketInterface socket = - WebSocketInterface('ws://127.0.0.1:4041/sip', messageDelay: 0); - Transport trasnport = Transport([socket]); + SIPUAWebSocket socket = + SIPUAWebSocket('ws://127.0.0.1:4041/sip', messageDelay: 0); + SocketTransport trasnport = + SocketTransport([socket]); - trasnport.onconnecting = (WebSocketInterface? socket, int? attempt) { + trasnport.onconnecting = (SIPUASocketInterface? socket, int? attempt) { expect(trasnport.isConnecting(), true); }; - trasnport.onconnect = (Transport socket) { + trasnport.onconnect = (SocketTransport socket) { expect(trasnport.isConnected(), true); trasnport.send('message'); }; - trasnport.ondata = (Transport transport, String messageData) { + trasnport.ondata = (SocketTransport transport, String messageData) { // expect(socket['message'], 'message'); trasnport.disconnect(); }; trasnport.ondisconnect = - (WebSocketInterface? socket, ErrorCause cause) { + (SIPUASocketInterface? socket, ErrorCause cause) { expect(trasnport.isConnected(), false); completer.complete(); };