1 /* 2 * libjingle SCTP 3 * Copyright 2012 Google Inc, and Robin Seggelmann 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #ifndef TALK_MEDIA_SCTP_SCTPDATAENGINE_H_ 29 #define TALK_MEDIA_SCTP_SCTPDATAENGINE_H_ 30 31 #include <errno.h> 32 #include <string> 33 #include <vector> 34 35 namespace cricket { 36 // Some ERRNO values get re-#defined to WSA* equivalents in some talk/ 37 // headers. We save the original ones in an enum. 38 enum PreservedErrno { 39 SCTP_EINPROGRESS = EINPROGRESS, 40 SCTP_EWOULDBLOCK = EWOULDBLOCK 41 }; 42 } // namespace cricket 43 44 #include "talk/base/buffer.h" 45 #include "talk/base/scoped_ptr.h" 46 #include "talk/media/base/codec.h" 47 #include "talk/media/base/mediachannel.h" 48 #include "talk/media/base/mediaengine.h" 49 50 // Defined by "usrsctplib/usrsctp.h" 51 struct sockaddr_conn; 52 struct sctp_assoc_change; 53 // Defined by <sys/socket.h> 54 struct socket; 55 56 namespace cricket { 57 // A DataEngine that interacts with usrsctp. 58 // 59 // From channel calls, data flows like this: 60 // [worker thread (although it can in princple be another thread)] 61 // 1. SctpDataMediaChannel::SendData(data) 62 // 2. usrsctp_sendv(data) 63 // [worker thread returns; sctp thread then calls the following] 64 // 3. OnSctpOutboundPacket(wrapped_data) 65 // [sctp thread returns having posted a message for the worker thread] 66 // 4. SctpDataMediaChannel::OnMessage(wrapped_data) 67 // 5. SctpDataMediaChannel::OnPacketFromSctpToNetwork(wrapped_data) 68 // 6. NetworkInterface::SendPacket(wrapped_data) 69 // 7. ... across network ... a packet is sent back ... 70 // 8. SctpDataMediaChannel::OnPacketReceived(wrapped_data) 71 // 9. usrsctp_conninput(wrapped_data) 72 // [worker thread returns; sctp thread then calls the following] 73 // 10. OnSctpInboundData(data) 74 // [sctp thread returns having posted a message fot the worker thread] 75 // 11. SctpDataMediaChannel::OnMessage(inboundpacket) 76 // 12. SctpDataMediaChannel::OnInboundPacketFromSctpToChannel(inboundpacket) 77 // 13. SctpDataMediaChannel::OnDataFromSctpToChannel(data) 78 // 14. SctpDataMediaChannel::SignalDataReceived(data) 79 // [from the same thread, methods registered/connected to 80 // SctpDataMediaChannel are called with the recieved data] 81 class SctpDataEngine : public DataEngineInterface { 82 public: 83 SctpDataEngine(); 84 virtual ~SctpDataEngine(); 85 86 virtual DataMediaChannel* CreateChannel(DataChannelType data_channel_type); 87 88 virtual const std::vector<DataCodec>& data_codecs() { return codecs_; } 89 90 private: 91 static int usrsctp_engines_count; 92 std::vector<DataCodec> codecs_; 93 }; 94 95 // TODO(ldixon): Make into a special type of TypedMessageData. 96 // Holds data to be passed on to a channel. 97 struct SctpInboundPacket; 98 99 class SctpDataMediaChannel : public DataMediaChannel, 100 public talk_base::MessageHandler { 101 public: 102 // DataMessageType is used for the SCTP "Payload Protocol Identifier", as 103 // defined in http://tools.ietf.org/html/rfc4960#section-14.4 104 // 105 // For the list of IANA approved values see: 106 // http://www.iana.org/assignments/sctp-parameters/sctp-parameters.xml 107 // The value is not used by SCTP itself. It indicates the protocol running 108 // on top of SCTP. 109 enum PayloadProtocolIdentifier { 110 PPID_NONE = 0, // No protocol is specified. 111 // Specified by Mozilla. Not clear that this is actually part of the 112 // standard. Use with caution! 113 // http://mxr.mozilla.org/mozilla-central/source/netwerk/sctp/datachannel/DataChannelProtocol.h#22 114 PPID_CONTROL = 50, 115 PPID_TEXT = 51, 116 PPID_BINARY = 52, 117 }; 118 119 // Given a thread which will be used to post messages (received data) to this 120 // SctpDataMediaChannel instance. 121 explicit SctpDataMediaChannel(talk_base::Thread* thread); 122 virtual ~SctpDataMediaChannel(); 123 124 // When SetSend is set to true, connects. When set to false, disconnects. 125 // Calling: "SetSend(true); SetSend(false); SetSend(true);" will connect, 126 // disconnect, and reconnect. 127 virtual bool SetSend(bool send); 128 // Unless SetReceive(true) is called, received packets will be discarded. 129 virtual bool SetReceive(bool receive); 130 131 virtual bool AddSendStream(const StreamParams& sp); 132 virtual bool RemoveSendStream(uint32 ssrc); 133 virtual bool AddRecvStream(const StreamParams& sp); 134 virtual bool RemoveRecvStream(uint32 ssrc); 135 136 // Called when Sctp gets data. The data may be a notification or data for 137 // OnSctpInboundData. Called from the worker thread. 138 virtual void OnMessage(talk_base::Message* msg); 139 // Send data down this channel (will be wrapped as SCTP packets then given to 140 // sctp that will then post the network interface by OnMessage). 141 // Returns true iff successful data somewhere on the send-queue/network. 142 virtual bool SendData(const SendDataParams& params, 143 const talk_base::Buffer& payload, 144 SendDataResult* result = NULL); 145 // A packet is received from the network interface. Posted to OnMessage. 146 virtual void OnPacketReceived(talk_base::Buffer* packet); 147 148 // Exposed to allow Post call from c-callbacks. 149 talk_base::Thread* worker_thread() const { return worker_thread_; } 150 151 // TODO(ldixon): add a DataOptions class to mediachannel.h 152 virtual bool SetOptions(int options) { return false; } 153 virtual int GetOptions() const { return 0; } 154 155 // Many of these things are unused by SCTP, but are needed to fulfill 156 // the MediaChannel interface. 157 // TODO(pthatcher): Cleanup MediaChannel interface, or at least 158 // don't try calling these and return false. Right now, things 159 // don't work if we return false. 160 virtual bool SetSendBandwidth(bool autobw, int bps) { return true; } 161 virtual bool SetRecvRtpHeaderExtensions( 162 const std::vector<RtpHeaderExtension>& extensions) { return true; } 163 virtual bool SetSendRtpHeaderExtensions( 164 const std::vector<RtpHeaderExtension>& extensions) { return true; } 165 virtual bool SetSendCodecs(const std::vector<DataCodec>& codecs) { 166 return true; 167 } 168 virtual bool SetRecvCodecs(const std::vector<DataCodec>& codecs) { 169 return true; 170 } 171 virtual void OnRtcpReceived(talk_base::Buffer* packet) {} 172 virtual void OnReadyToSend(bool ready) {} 173 174 // Helper for debugging. 175 void set_debug_name(const std::string& debug_name) { 176 debug_name_ = debug_name; 177 } 178 const std::string& debug_name() const { return debug_name_; } 179 180 private: 181 sockaddr_conn GetSctpSockAddr(int port); 182 183 // Creates the socket and connects. Sets sending_ to true. 184 bool Connect(); 185 // Closes the socket. Sets sending_ to false. 186 void Disconnect(); 187 188 // Returns false when openning the socket failed; when successfull sets 189 // sending_ to true 190 bool OpenSctpSocket(); 191 // Sets sending_ to false and sock_ to NULL. 192 void CloseSctpSocket(); 193 194 // Called by OnMessage to send packet on the network. 195 void OnPacketFromSctpToNetwork(talk_base::Buffer* buffer); 196 // Called by OnMessage to decide what to do with the packet. 197 void OnInboundPacketFromSctpToChannel(SctpInboundPacket* packet); 198 void OnDataFromSctpToChannel(const ReceiveDataParams& params, 199 talk_base::Buffer* buffer); 200 void OnNotificationFromSctp(talk_base::Buffer* buffer); 201 void OnNotificationAssocChange(const sctp_assoc_change& change); 202 203 // Responsible for marshalling incoming data to the channels listeners, and 204 // outgoing data to the network interface. 205 talk_base::Thread* worker_thread_; 206 // The local and remote SCTP port to use. These are passed along the wire 207 // and the listener and connector must be using the same port. It is not 208 // related to the ports at the IP level. 209 int local_port_; 210 int remote_port_; 211 // TODO(ldixon): investigate why removing 'struct' makes the compiler 212 // complain. 213 // 214 // The socket created by usrsctp_socket(...). 215 struct socket* sock_; 216 217 // sending_ is true iff there is a connected socket. 218 bool sending_; 219 // receiving_ controls whether inbound packets are thrown away. 220 bool receiving_; 221 // Unified send/receive streams, as each is bidirectional. 222 std::vector<StreamParams> streams_; 223 224 // A human-readable name for debugging messages. 225 std::string debug_name_; 226 }; 227 228 } // namespace cricket 229 230 #endif // TALK_MEDIA_SCTP_SCTPDATAENGINE_H_ 231