OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2012 Google Inc. and Robin Seggelmann | 3 * Copyright 2012 Google Inc. and Robin Seggelmann |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 } // namespace | 102 } // namespace |
103 | 103 |
104 namespace cricket { | 104 namespace cricket { |
105 typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage; | 105 typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage; |
106 typedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage; | 106 typedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage; |
107 | 107 |
108 // The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280, | 108 // The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280, |
109 // take off 80 bytes for DTLS/TURN/TCP/IP overhead. | 109 // take off 80 bytes for DTLS/TURN/TCP/IP overhead. |
110 static const size_t kSctpMtu = 1200; | 110 static const size_t kSctpMtu = 1200; |
111 | 111 |
112 // The size of the SCTP association send buffer. 256kB, the usrsctp default. | |
113 static const int kSendBufferSize = 262144; | |
114 enum { | 112 enum { |
115 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket | 113 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket |
116 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer | 114 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer |
117 }; | 115 }; |
118 | 116 |
119 struct SctpInboundPacket { | 117 struct SctpInboundPacket { |
120 rtc::Buffer buffer; | 118 rtc::Buffer buffer; |
121 ReceiveDataParams params; | 119 ReceiveDataParams params; |
122 // The |flags| parameter is used by SCTP to distinguish notification packets | 120 // The |flags| parameter is used by SCTP to distinguish notification packets |
123 // from other types of packets. | 121 // from other types of packets. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 case SctpDataMediaChannel::PPID_NONE: | 170 case SctpDataMediaChannel::PPID_NONE: |
173 *dest = cricket::DMT_NONE; | 171 *dest = cricket::DMT_NONE; |
174 return true; | 172 return true; |
175 | 173 |
176 default: | 174 default: |
177 return false; | 175 return false; |
178 } | 176 } |
179 } | 177 } |
180 | 178 |
181 // Log the packet in text2pcap format, if log level is at LS_VERBOSE. | 179 // Log the packet in text2pcap format, if log level is at LS_VERBOSE. |
182 static void VerboseLogPacket(void *data, size_t length, int direction) { | 180 static void VerboseLogPacket(void *addr, size_t length, int direction) { |
183 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { | 181 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { |
184 char *dump_buf; | 182 char *dump_buf; |
185 if ((dump_buf = usrsctp_dumppacket( | 183 if ((dump_buf = usrsctp_dumppacket( |
186 data, length, direction)) != NULL) { | 184 addr, length, direction)) != NULL) { |
187 LOG(LS_VERBOSE) << dump_buf; | 185 LOG(LS_VERBOSE) << dump_buf; |
188 usrsctp_freedumpbuffer(dump_buf); | 186 usrsctp_freedumpbuffer(dump_buf); |
189 } | 187 } |
190 } | 188 } |
191 } | 189 } |
192 | 190 |
193 // This is the callback usrsctp uses when there's data to send on the network | 191 // This is the callback usrsctp uses when there's data to send on the network |
194 // that has been wrapped appropriatly for the SCTP protocol. | 192 // that has been wrapped appropriatly for the SCTP protocol. |
195 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, | 193 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, |
196 uint8_t tos, uint8_t set_df) { | 194 uint8_t tos, uint8_t set_df) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 // The ownership of |packet| transfers to |msg|. | 237 // The ownership of |packet| transfers to |msg|. |
240 InboundPacketMessage* msg = new InboundPacketMessage(packet); | 238 InboundPacketMessage* msg = new InboundPacketMessage(packet); |
241 channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET, msg); | 239 channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET, msg); |
242 } | 240 } |
243 free(data); | 241 free(data); |
244 return 1; | 242 return 1; |
245 } | 243 } |
246 | 244 |
247 // Set the initial value of the static SCTP Data Engines reference count. | 245 // Set the initial value of the static SCTP Data Engines reference count. |
248 int SctpDataEngine::usrsctp_engines_count = 0; | 246 int SctpDataEngine::usrsctp_engines_count = 0; |
249 // All the channels created by this engine, used for callbacks from | |
250 // usrsctplib that only contain socket pointers. Channels are removed when | |
251 // SignalDestroyed is fired. | |
252 std::vector<SctpDataMediaChannel*> SctpDataEngine::channels_; | |
253 | 247 |
254 SctpDataEngine::SctpDataEngine() { | 248 SctpDataEngine::SctpDataEngine() { |
255 if (usrsctp_engines_count == 0) { | 249 if (usrsctp_engines_count == 0) { |
256 // First argument is udp_encapsulation_port, which is not releveant for our | 250 // First argument is udp_encapsulation_port, which is not releveant for our |
257 // AF_CONN use of sctp. | 251 // AF_CONN use of sctp. |
258 usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf); | 252 usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf); |
259 | 253 |
260 // To turn on/off detailed SCTP debugging. You will also need to have the | 254 // To turn on/off detailed SCTP debugging. You will also need to have the |
261 // SCTP_DEBUG cpp defines flag. | 255 // SCTP_DEBUG cpp defines flag. |
262 // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); | 256 // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); |
263 | 257 |
264 // TODO(ldixon): Consider turning this on/off. | 258 // TODO(ldixon): Consider turning this on/off. |
265 usrsctp_sysctl_set_sctp_ecn_enable(0); | 259 usrsctp_sysctl_set_sctp_ecn_enable(0); |
266 | 260 |
267 int send_size = usrsctp_sysctl_get_sctp_sendspace(); | |
268 if (send_size != kSendBufferSize) { | |
269 LOG(LS_ERROR) << "Got different send size than expected: " << send_size; | |
270 } | |
271 | |
272 // TODO(ldixon): Consider turning this on/off. | 261 // TODO(ldixon): Consider turning this on/off. |
273 // This is not needed right now (we don't do dynamic address changes): | 262 // This is not needed right now (we don't do dynamic address changes): |
274 // If SCTP Auto-ASCONF is enabled, the peer is informed automatically | 263 // If SCTP Auto-ASCONF is enabled, the peer is informed automatically |
275 // when a new address is added or removed. This feature is enabled by | 264 // when a new address is added or removed. This feature is enabled by |
276 // default. | 265 // default. |
277 // usrsctp_sysctl_set_sctp_auto_asconf(0); | 266 // usrsctp_sysctl_set_sctp_auto_asconf(0); |
278 | 267 |
279 // TODO(ldixon): Consider turning this on/off. | 268 // TODO(ldixon): Consider turning this on/off. |
280 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs | 269 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs |
281 // being sent in response to INITs, setting it to 2 results | 270 // being sent in response to INITs, setting it to 2 results |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 } | 305 } |
317 LOG(LS_ERROR) << "Failed to shutdown usrsctp."; | 306 LOG(LS_ERROR) << "Failed to shutdown usrsctp."; |
318 } | 307 } |
319 } | 308 } |
320 | 309 |
321 DataMediaChannel* SctpDataEngine::CreateChannel( | 310 DataMediaChannel* SctpDataEngine::CreateChannel( |
322 DataChannelType data_channel_type) { | 311 DataChannelType data_channel_type) { |
323 if (data_channel_type != DCT_SCTP) { | 312 if (data_channel_type != DCT_SCTP) { |
324 return NULL; | 313 return NULL; |
325 } | 314 } |
326 SctpDataMediaChannel *channel = new SctpDataMediaChannel( | 315 return new SctpDataMediaChannel(rtc::Thread::Current()); |
327 rtc::Thread::Current()); | |
328 channels_.push_back(channel); | |
329 channel->SignalDestroyed.connect(this, &SctpDataEngine::OnChannelDestroyed); | |
330 return channel; | |
331 } | 316 } |
332 | 317 |
333 // static | |
334 SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket( | |
335 struct socket* sock) { | |
336 for (auto p:channels_) { | |
337 if (p->socket() == sock) { | |
338 return p; | |
339 } | |
340 } | |
341 return 0; | |
342 } | |
343 | |
344 | |
345 void SctpDataEngine::OnChannelDestroyed(SctpDataMediaChannel* channel) { | |
346 auto it = std::find(channels_.begin(), channels_.end(), channel); | |
347 if (it == channels_.end()) { | |
348 LOG(LS_ERROR) << "OnChannelDestroyed: the channel wasn't registered."; | |
349 return; | |
350 } | |
351 channels_.erase(it); | |
352 } | |
353 | |
354 // static | |
355 int SctpDataEngine::SendThresholdCallback(struct socket* sock, | |
356 uint32_t sb_free) { | |
357 SctpDataMediaChannel *channel = GetChannelFromSocket(sock); | |
358 if (!channel) { | |
359 LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket " | |
360 << sock; | |
361 return 0; | |
362 } | |
363 channel->SignalReadyToSend(true); | |
364 return 0; | |
365 } | |
366 | |
367 | |
368 SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread) | 318 SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread) |
369 : worker_thread_(thread), | 319 : worker_thread_(thread), |
370 local_port_(kSctpDefaultPort), | 320 local_port_(kSctpDefaultPort), |
371 remote_port_(kSctpDefaultPort), | 321 remote_port_(kSctpDefaultPort), |
372 sock_(NULL), | 322 sock_(NULL), |
373 sending_(false), | 323 sending_(false), |
374 receiving_(false), | 324 receiving_(false), |
375 debug_name_("SctpDataMediaChannel") { | 325 debug_name_("SctpDataMediaChannel") { |
376 } | 326 } |
377 | 327 |
378 SctpDataMediaChannel::~SctpDataMediaChannel() { | 328 SctpDataMediaChannel::~SctpDataMediaChannel() { |
379 CloseSctpSocket(); | 329 CloseSctpSocket(); |
380 SignalDestroyed(this); | |
381 } | 330 } |
382 | 331 |
383 sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) { | 332 sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) { |
384 sockaddr_conn sconn = {0}; | 333 sockaddr_conn sconn = {0}; |
385 sconn.sconn_family = AF_CONN; | 334 sconn.sconn_family = AF_CONN; |
386 #ifdef HAVE_SCONN_LEN | 335 #ifdef HAVE_SCONN_LEN |
387 sconn.sconn_len = sizeof(sockaddr_conn); | 336 sconn.sconn_len = sizeof(sockaddr_conn); |
388 #endif | 337 #endif |
389 // Note: conversion from int to uint16_t happens here. | 338 // Note: conversion from int to uint16_t happens here. |
390 sconn.sconn_port = rtc::HostToNetwork16(port); | 339 sconn.sconn_port = rtc::HostToNetwork16(port); |
391 sconn.sconn_addr = this; | 340 sconn.sconn_addr = this; |
392 return sconn; | 341 return sconn; |
393 } | 342 } |
394 | 343 |
395 bool SctpDataMediaChannel::OpenSctpSocket() { | 344 bool SctpDataMediaChannel::OpenSctpSocket() { |
396 if (sock_) { | 345 if (sock_) { |
397 LOG(LS_VERBOSE) << debug_name_ | 346 LOG(LS_VERBOSE) << debug_name_ |
398 << "->Ignoring attempt to re-create existing socket."; | 347 << "->Ignoring attempt to re-create existing socket."; |
399 return false; | 348 return false; |
400 } | 349 } |
401 | |
402 // If kSendBufferSize isn't reflective of reality, we log an error, but we | |
403 // still have to do something reasonable here. Look up what the buffer's | |
404 // real size is and set our threshold to something reasonable. | |
405 const static int send_threshold = usrsctp_sysctl_get_sctp_sendspace() / 2; | |
406 | |
407 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, | 350 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, |
408 cricket::OnSctpInboundPacket, | 351 cricket::OnSctpInboundPacket, NULL, 0, this); |
409 &SctpDataEngine::SendThresholdCallback, | |
410 send_threshold, this); | |
411 if (!sock_) { | 352 if (!sock_) { |
412 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; | 353 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; |
413 return false; | 354 return false; |
414 } | 355 } |
415 | 356 |
416 // Make the socket non-blocking. Connect, close, shutdown etc will not block | 357 // Make the socket non-blocking. Connect, close, shutdown etc will not block |
417 // the thread waiting for the socket operation to complete. | 358 // the thread waiting for the socket operation to complete. |
418 if (usrsctp_set_non_blocking(sock_, 1) < 0) { | 359 if (usrsctp_set_non_blocking(sock_, 1) < 0) { |
419 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; | 360 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; |
420 return false; | 361 return false; |
(...skipping 24 matching lines...) Expand all Loading... |
445 | 386 |
446 // Nagle. | 387 // Nagle. |
447 uint32_t nodelay = 1; | 388 uint32_t nodelay = 1; |
448 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, | 389 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, |
449 sizeof(nodelay))) { | 390 sizeof(nodelay))) { |
450 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY."; | 391 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY."; |
451 return false; | 392 return false; |
452 } | 393 } |
453 | 394 |
454 // Disable MTU discovery | 395 // Disable MTU discovery |
455 struct sctp_paddrparams params; | 396 struct sctp_paddrparams params = {{0}}; |
456 memset(¶ms, 0, sizeof(params)); | |
457 params.spp_assoc_id = 0; | 397 params.spp_assoc_id = 0; |
458 params.spp_flags = SPP_PMTUD_DISABLE; | 398 params.spp_flags = SPP_PMTUD_DISABLE; |
459 params.spp_pathmtu = kSctpMtu; | 399 params.spp_pathmtu = kSctpMtu; |
460 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, | 400 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, |
461 sizeof(params))) { | 401 sizeof(params))) { |
462 LOG_ERRNO(LS_ERROR) << debug_name_ | 402 LOG_ERRNO(LS_ERROR) << debug_name_ |
463 << "Failed to set SCTP_PEER_ADDR_PARAMS."; | 403 << "Failed to set SCTP_PEER_ADDR_PARAMS."; |
464 return false; | 404 return false; |
465 } | 405 } |
466 | 406 |
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
957 } | 897 } |
958 | 898 |
959 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { | 899 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { |
960 return GetCodecIntParameter( | 900 return GetCodecIntParameter( |
961 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort, | 901 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort, |
962 &local_port_); | 902 &local_port_); |
963 } | 903 } |
964 | 904 |
965 void SctpDataMediaChannel::OnPacketFromSctpToNetwork( | 905 void SctpDataMediaChannel::OnPacketFromSctpToNetwork( |
966 rtc::Buffer* buffer) { | 906 rtc::Buffer* buffer) { |
967 // usrsctp seems to interpret the MTU we give it strangely -- it seems to | 907 if (buffer->size() > kSctpMtu) { |
968 // give us back packets bigger than that MTU, if only by a fixed amount. | |
969 // This is that amount that we've observed. | |
970 const int kSctpOverhead = 76; | |
971 if (buffer->size() > (kSctpOverhead + kSctpMtu)) { | |
972 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): " | 908 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): " |
973 << "SCTP seems to have made a packet that is bigger " | 909 << "SCTP seems to have made a packet that is bigger " |
974 << "than its official MTU: " << buffer->size() | 910 "than its official MTU."; |
975 << " vs max of " << kSctpMtu | |
976 << " even after adding " << kSctpOverhead | |
977 << " extra SCTP overhead"; | |
978 } | 911 } |
979 MediaChannel::SendPacket(buffer); | 912 MediaChannel::SendPacket(buffer); |
980 } | 913 } |
981 | 914 |
982 bool SctpDataMediaChannel::SendQueuedStreamResets() { | 915 bool SctpDataMediaChannel::SendQueuedStreamResets() { |
983 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) | 916 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) |
984 return true; | 917 return true; |
985 | 918 |
986 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending [" | 919 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending [" |
987 << ListStreams(queued_reset_streams_) << "], Open: [" | 920 << ListStreams(queued_reset_streams_) << "], Open: [" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1029 } | 962 } |
1030 case MSG_SCTPOUTBOUNDPACKET: { | 963 case MSG_SCTPOUTBOUNDPACKET: { |
1031 rtc::scoped_ptr<OutboundPacketMessage> pdata( | 964 rtc::scoped_ptr<OutboundPacketMessage> pdata( |
1032 static_cast<OutboundPacketMessage*>(msg->pdata)); | 965 static_cast<OutboundPacketMessage*>(msg->pdata)); |
1033 OnPacketFromSctpToNetwork(pdata->data().get()); | 966 OnPacketFromSctpToNetwork(pdata->data().get()); |
1034 break; | 967 break; |
1035 } | 968 } |
1036 } | 969 } |
1037 } | 970 } |
1038 } // namespace cricket | 971 } // namespace cricket |
OLD | NEW |