Chromium Code Reviews| 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; | |
| 112 enum { | 114 enum { |
| 113 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket | 115 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket |
| 114 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer | 116 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer |
| 115 }; | 117 }; |
| 116 | 118 |
| 117 struct SctpInboundPacket { | 119 struct SctpInboundPacket { |
| 118 rtc::Buffer buffer; | 120 rtc::Buffer buffer; |
| 119 ReceiveDataParams params; | 121 ReceiveDataParams params; |
| 120 // The |flags| parameter is used by SCTP to distinguish notification packets | 122 // The |flags| parameter is used by SCTP to distinguish notification packets |
| 121 // from other types of packets. | 123 // from other types of packets. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 170 case SctpDataMediaChannel::PPID_NONE: | 172 case SctpDataMediaChannel::PPID_NONE: |
| 171 *dest = cricket::DMT_NONE; | 173 *dest = cricket::DMT_NONE; |
| 172 return true; | 174 return true; |
| 173 | 175 |
| 174 default: | 176 default: |
| 175 return false; | 177 return false; |
| 176 } | 178 } |
| 177 } | 179 } |
| 178 | 180 |
| 179 // Log the packet in text2pcap format, if log level is at LS_VERBOSE. | 181 // Log the packet in text2pcap format, if log level is at LS_VERBOSE. |
| 180 static void VerboseLogPacket(void *addr, size_t length, int direction) { | 182 static void VerboseLogPacket(void *data, size_t length, int direction) { |
| 181 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { | 183 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { |
| 182 char *dump_buf; | 184 char *dump_buf; |
| 183 if ((dump_buf = usrsctp_dumppacket( | 185 if ((dump_buf = usrsctp_dumppacket( |
| 184 addr, length, direction)) != NULL) { | 186 data, length, direction)) != NULL) { |
| 185 LOG(LS_VERBOSE) << dump_buf; | 187 LOG(LS_VERBOSE) << dump_buf; |
| 186 usrsctp_freedumpbuffer(dump_buf); | 188 usrsctp_freedumpbuffer(dump_buf); |
| 187 } | 189 } |
| 188 } | 190 } |
| 189 } | 191 } |
| 190 | 192 |
| 191 // This is the callback usrsctp uses when there's data to send on the network | 193 // This is the callback usrsctp uses when there's data to send on the network |
| 192 // that has been wrapped appropriatly for the SCTP protocol. | 194 // that has been wrapped appropriatly for the SCTP protocol. |
| 193 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, | 195 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, |
| 194 uint8_t tos, uint8_t set_df) { | 196 uint8_t tos, uint8_t set_df) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 251 // AF_CONN use of sctp. | 253 // AF_CONN use of sctp. |
| 252 usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf); | 254 usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf); |
| 253 | 255 |
| 254 // To turn on/off detailed SCTP debugging. You will also need to have the | 256 // To turn on/off detailed SCTP debugging. You will also need to have the |
| 255 // SCTP_DEBUG cpp defines flag. | 257 // SCTP_DEBUG cpp defines flag. |
| 256 // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); | 258 // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); |
| 257 | 259 |
| 258 // TODO(ldixon): Consider turning this on/off. | 260 // TODO(ldixon): Consider turning this on/off. |
| 259 usrsctp_sysctl_set_sctp_ecn_enable(0); | 261 usrsctp_sysctl_set_sctp_ecn_enable(0); |
| 260 | 262 |
| 263 int send_size = usrsctp_sysctl_get_sctp_sendspace(); | |
| 264 if (send_size != kSendBufferSize) { | |
| 265 LOG(LS_ERROR) << "Got different send size than expected: " << send_size; | |
|
tommi
2015/08/28 11:44:04
is it still ok to continue? what are the implicat
lally1
2015/08/28 17:54:48
Harmless check, it's been documented.
| |
| 266 } | |
| 267 | |
| 261 // TODO(ldixon): Consider turning this on/off. | 268 // TODO(ldixon): Consider turning this on/off. |
| 262 // This is not needed right now (we don't do dynamic address changes): | 269 // This is not needed right now (we don't do dynamic address changes): |
| 263 // If SCTP Auto-ASCONF is enabled, the peer is informed automatically | 270 // If SCTP Auto-ASCONF is enabled, the peer is informed automatically |
| 264 // when a new address is added or removed. This feature is enabled by | 271 // when a new address is added or removed. This feature is enabled by |
| 265 // default. | 272 // default. |
| 266 // usrsctp_sysctl_set_sctp_auto_asconf(0); | 273 // usrsctp_sysctl_set_sctp_auto_asconf(0); |
| 267 | 274 |
| 268 // TODO(ldixon): Consider turning this on/off. | 275 // TODO(ldixon): Consider turning this on/off. |
| 269 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs | 276 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs |
| 270 // being sent in response to INITs, setting it to 2 results | 277 // being sent in response to INITs, setting it to 2 results |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 308 } | 315 } |
| 309 | 316 |
| 310 DataMediaChannel* SctpDataEngine::CreateChannel( | 317 DataMediaChannel* SctpDataEngine::CreateChannel( |
| 311 DataChannelType data_channel_type) { | 318 DataChannelType data_channel_type) { |
| 312 if (data_channel_type != DCT_SCTP) { | 319 if (data_channel_type != DCT_SCTP) { |
| 313 return NULL; | 320 return NULL; |
| 314 } | 321 } |
| 315 return new SctpDataMediaChannel(rtc::Thread::Current()); | 322 return new SctpDataMediaChannel(rtc::Thread::Current()); |
| 316 } | 323 } |
| 317 | 324 |
| 325 // static | |
| 326 SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket( | |
| 327 struct socket* sock) { | |
| 328 struct sockaddr* addrs; | |
|
tommi
2015/08/28 11:44:04
= nullptr;
lally1
2015/08/28 17:54:48
Done.
| |
| 329 int naddrs; | |
|
tommi
2015/08/28 11:44:04
declare where needed.
lally1
2015/08/28 17:54:48
Done.
| |
| 330 SctpDataMediaChannel* channel = 0; | |
|
tommi
2015/08/28 11:44:04
= nullptr;
lally1
2015/08/28 17:54:48
Done.
| |
| 331 naddrs = usrsctp_getladdrs(sock, 0, &addrs); | |
| 332 if (naddrs >= 0) { | |
|
tommi
2015/08/28 11:44:04
nit: what about bailing out in case of errors and
lally1
2015/08/28 17:54:49
Done.
| |
| 333 if (naddrs > 0) { | |
| 334 if (addrs[0].sa_family == AF_CONN) { | |
|
tommi
2015/08/28 11:44:04
I'm not familiar with what the returned order will
lally1
2015/08/28 17:54:48
Documented.
| |
| 335 struct sockaddr_conn* sconn = (struct sockaddr_conn*) &addrs[0]; | |
|
tommi
2015/08/28 11:44:04
here and elsewhere, use C++ casts
(reinterpret_cas
lally1
2015/08/28 17:54:49
Done.
| |
| 336 channel = (SctpDataMediaChannel*) sconn->sconn_addr; | |
| 337 } | |
| 338 } | |
| 339 usrsctp_freeladdrs(addrs); | |
| 340 } | |
| 341 | |
| 342 return channel; | |
| 343 } | |
| 344 | |
| 345 | |
| 346 // static | |
| 347 int SctpDataEngine::SendThresholdCallback(struct socket* sock, | |
| 348 uint32_t sb_free) { | |
| 349 SctpDataMediaChannel* channel = GetChannelFromSocket(sock); | |
|
tommi
2015/08/28 11:44:04
Add:
DCHECK(sock);
or better yet, do it in GetCh
lally1
2015/08/28 17:54:48
DCHECKs added to GetChannelFromSocket.
| |
| 350 if (!channel) { | |
| 351 LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket " | |
|
tommi
2015/08/28 11:44:04
you might want to defer this logging to GetChannel
lally1
2015/08/28 17:54:48
Acknowledged.
| |
| 352 << sock; | |
| 353 } | |
| 354 channel->SignalReadyToSend(true); | |
|
tommi
2015/08/28 11:44:04
Another thing... here we're firing a signal for th
tommi
2015/08/28 11:44:04
gaa.... here you might be dereferencing a nullptr
lally1
2015/08/28 17:54:48
We have the appropriate rtc::Thread as a member, s
lally1
2015/08/28 17:54:48
Good catch.
| |
| 355 return 0; | |
| 356 } | |
| 357 | |
| 318 SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread) | 358 SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread) |
| 319 : worker_thread_(thread), | 359 : worker_thread_(thread), |
| 320 local_port_(kSctpDefaultPort), | 360 local_port_(kSctpDefaultPort), |
| 321 remote_port_(kSctpDefaultPort), | 361 remote_port_(kSctpDefaultPort), |
| 322 sock_(NULL), | 362 sock_(NULL), |
| 323 sending_(false), | 363 sending_(false), |
| 324 receiving_(false), | 364 receiving_(false), |
| 325 debug_name_("SctpDataMediaChannel") { | 365 debug_name_("SctpDataMediaChannel") { |
| 326 } | 366 } |
| 327 | 367 |
| 328 SctpDataMediaChannel::~SctpDataMediaChannel() { | 368 SctpDataMediaChannel::~SctpDataMediaChannel() { |
| 329 CloseSctpSocket(); | 369 CloseSctpSocket(); |
| 330 } | 370 } |
| 331 | 371 |
| 332 sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) { | 372 sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) { |
| 333 sockaddr_conn sconn = {0}; | 373 sockaddr_conn sconn = {0}; |
| 334 sconn.sconn_family = AF_CONN; | 374 sconn.sconn_family = AF_CONN; |
| 335 #ifdef HAVE_SCONN_LEN | 375 #ifdef HAVE_SCONN_LEN |
| 336 sconn.sconn_len = sizeof(sockaddr_conn); | 376 sconn.sconn_len = sizeof(sockaddr_conn); |
| 337 #endif | 377 #endif |
| 338 // Note: conversion from int to uint16_t happens here. | 378 // Note: conversion from int to uint16_t happens here. |
| 339 sconn.sconn_port = rtc::HostToNetwork16(port); | 379 sconn.sconn_port = rtc::HostToNetwork16(port); |
| 340 sconn.sconn_addr = this; | 380 sconn.sconn_addr = this; |
| 341 return sconn; | 381 return sconn; |
| 342 } | 382 } |
| 343 | 383 |
| 344 bool SctpDataMediaChannel::OpenSctpSocket() { | 384 bool SctpDataMediaChannel::OpenSctpSocket() { |
|
tommi
2015/08/28 11:44:04
as a general comment, since these methods do not h
| |
| 345 if (sock_) { | 385 if (sock_) { |
| 346 LOG(LS_VERBOSE) << debug_name_ | 386 LOG(LS_VERBOSE) << debug_name_ |
| 347 << "->Ignoring attempt to re-create existing socket."; | 387 << "->Ignoring attempt to re-create existing socket."; |
| 348 return false; | 388 return false; |
| 349 } | 389 } |
| 390 | |
| 391 // If kSendBufferSize isn't reflective of reality, we log an error, but we | |
| 392 // still have to do something reasonable here. Look up what the buffer's | |
| 393 // real size is and set our threshold to something reasonable. | |
| 394 const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2; | |
| 395 | |
| 350 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, | 396 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, |
| 351 cricket::OnSctpInboundPacket, NULL, 0, this); | 397 cricket::OnSctpInboundPacket, |
| 398 &SctpDataEngine::SendThresholdCallback, | |
| 399 kSendThreshold, this); | |
| 352 if (!sock_) { | 400 if (!sock_) { |
| 353 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; | 401 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; |
| 354 return false; | 402 return false; |
| 355 } | 403 } |
| 356 | 404 |
| 357 // Make the socket non-blocking. Connect, close, shutdown etc will not block | 405 // Make the socket non-blocking. Connect, close, shutdown etc will not block |
| 358 // the thread waiting for the socket operation to complete. | 406 // the thread waiting for the socket operation to complete. |
| 359 if (usrsctp_set_non_blocking(sock_, 1) < 0) { | 407 if (usrsctp_set_non_blocking(sock_, 1) < 0) { |
| 360 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; | 408 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; |
| 361 return false; | 409 return false; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 386 | 434 |
| 387 // Nagle. | 435 // Nagle. |
| 388 uint32_t nodelay = 1; | 436 uint32_t nodelay = 1; |
| 389 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, | 437 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, |
| 390 sizeof(nodelay))) { | 438 sizeof(nodelay))) { |
| 391 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY."; | 439 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY."; |
| 392 return false; | 440 return false; |
| 393 } | 441 } |
| 394 | 442 |
| 395 // Disable MTU discovery | 443 // Disable MTU discovery |
| 396 struct sctp_paddrparams params = {{0}}; | 444 struct sctp_paddrparams params; |
|
tommi
2015/08/28 11:44:03
nit: omit 'struct'
lally1
2015/08/28 17:54:48
Done.
| |
| 445 memset(¶ms, 0, sizeof(params)); | |
|
tommi
2015/08/28 11:44:04
if memset is doing more than = {}, then that sugge
lally1
2015/08/28 17:54:48
Done. I can't remember where it happened anymore,
| |
| 397 params.spp_assoc_id = 0; | 446 params.spp_assoc_id = 0; |
| 398 params.spp_flags = SPP_PMTUD_DISABLE; | 447 params.spp_flags = SPP_PMTUD_DISABLE; |
| 399 params.spp_pathmtu = kSctpMtu; | 448 params.spp_pathmtu = kSctpMtu; |
| 400 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, | 449 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, |
| 401 sizeof(params))) { | 450 sizeof(params))) { |
| 402 LOG_ERRNO(LS_ERROR) << debug_name_ | 451 LOG_ERRNO(LS_ERROR) << debug_name_ |
| 403 << "Failed to set SCTP_PEER_ADDR_PARAMS."; | 452 << "Failed to set SCTP_PEER_ADDR_PARAMS."; |
| 404 return false; | 453 return false; |
| 405 } | 454 } |
| 406 | 455 |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 897 } | 946 } |
| 898 | 947 |
| 899 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { | 948 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { |
| 900 return GetCodecIntParameter( | 949 return GetCodecIntParameter( |
| 901 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort, | 950 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort, |
| 902 &local_port_); | 951 &local_port_); |
| 903 } | 952 } |
| 904 | 953 |
| 905 void SctpDataMediaChannel::OnPacketFromSctpToNetwork( | 954 void SctpDataMediaChannel::OnPacketFromSctpToNetwork( |
| 906 rtc::Buffer* buffer) { | 955 rtc::Buffer* buffer) { |
| 907 if (buffer->size() > kSctpMtu) { | 956 // usrsctp seems to interpret the MTU we give it strangely -- it seems to |
| 957 // give us back packets bigger than that MTU, if only by a fixed amount. | |
| 958 // This is that amount that we've observed. | |
| 959 const int kSctpOverhead = 76; | |
| 960 if (buffer->size() > (kSctpOverhead + kSctpMtu)) { | |
| 908 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): " | 961 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): " |
| 909 << "SCTP seems to have made a packet that is bigger " | 962 << "SCTP seems to have made a packet that is bigger " |
| 910 "than its official MTU."; | 963 << "than its official MTU: " << buffer->size() |
| 964 << " vs max of " << kSctpMtu | |
| 965 << " even after adding " << kSctpOverhead | |
| 966 << " extra SCTP overhead"; | |
| 911 } | 967 } |
| 912 MediaChannel::SendPacket(buffer); | 968 MediaChannel::SendPacket(buffer); |
| 913 } | 969 } |
| 914 | 970 |
| 915 bool SctpDataMediaChannel::SendQueuedStreamResets() { | 971 bool SctpDataMediaChannel::SendQueuedStreamResets() { |
| 916 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) | 972 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) |
| 917 return true; | 973 return true; |
| 918 | 974 |
| 919 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending [" | 975 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending [" |
| 920 << ListStreams(queued_reset_streams_) << "], Open: [" | 976 << ListStreams(queued_reset_streams_) << "], Open: [" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 962 } | 1018 } |
| 963 case MSG_SCTPOUTBOUNDPACKET: { | 1019 case MSG_SCTPOUTBOUNDPACKET: { |
| 964 rtc::scoped_ptr<OutboundPacketMessage> pdata( | 1020 rtc::scoped_ptr<OutboundPacketMessage> pdata( |
| 965 static_cast<OutboundPacketMessage*>(msg->pdata)); | 1021 static_cast<OutboundPacketMessage*>(msg->pdata)); |
| 966 OnPacketFromSctpToNetwork(pdata->data().get()); | 1022 OnPacketFromSctpToNetwork(pdata->data().get()); |
| 967 break; | 1023 break; |
| 968 } | 1024 } |
| 969 } | 1025 } |
| 970 } | 1026 } |
| 971 } // namespace cricket | 1027 } // namespace cricket |
| OLD | NEW |