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 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
170 case SctpDataMediaChannel::PPID_NONE: | 170 case SctpDataMediaChannel::PPID_NONE: |
171 *dest = cricket::DMT_NONE; | 171 *dest = cricket::DMT_NONE; |
172 return true; | 172 return true; |
173 | 173 |
174 default: | 174 default: |
175 return false; | 175 return false; |
176 } | 176 } |
177 } | 177 } |
178 | 178 |
179 // 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. |
180 static void VerboseLogPacket(void *addr, size_t length, int direction) { | 180 static void VerboseLogPacket(void *data, size_t length, int direction) { |
181 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { | 181 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { |
182 char *dump_buf; | 182 char *dump_buf; |
183 if ((dump_buf = usrsctp_dumppacket( | 183 if ((dump_buf = usrsctp_dumppacket( |
184 addr, length, direction)) != NULL) { | 184 data, length, direction)) != NULL) { |
185 LOG(LS_VERBOSE) << dump_buf; | 185 LOG(LS_VERBOSE) << dump_buf; |
186 usrsctp_freedumpbuffer(dump_buf); | 186 usrsctp_freedumpbuffer(dump_buf); |
187 } | 187 } |
188 } | 188 } |
189 } | 189 } |
190 | 190 |
191 // 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 |
192 // that has been wrapped appropriatly for the SCTP protocol. | 192 // that has been wrapped appropriatly for the SCTP protocol. |
193 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, | 193 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, |
194 uint8_t tos, uint8_t set_df) { | 194 uint8_t tos, uint8_t set_df) { |
195 SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr); | 195 SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr); |
196 LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():" | 196 LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():" |
197 << "addr: " << addr << "; length: " << length | 197 << "addr: " << addr << "; length: " << length |
198 << "; tos: " << std::hex << static_cast<int>(tos) | 198 << "; tos: " << std::hex << static_cast<int>(tos) |
199 << "; set_df: " << std::hex << static_cast<int>(set_df); | 199 << "; set_df: " << std::hex << static_cast<int>(set_df); |
200 | 200 |
201 VerboseLogPacket(addr, length, SCTP_DUMP_OUTBOUND); | 201 VerboseLogPacket(data, length, SCTP_DUMP_OUTBOUND); |
202 // Note: We have to copy the data; the caller will delete it. | 202 // Note: We have to copy the data; the caller will delete it. |
203 auto* msg = new OutboundPacketMessage( | 203 auto* msg = new OutboundPacketMessage( |
204 new rtc::Buffer(reinterpret_cast<uint8_t*>(data), length)); | 204 new rtc::Buffer(reinterpret_cast<uint8_t*>(data), length)); |
205 channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg); | 205 channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg); |
206 return 0; | 206 return 0; |
207 } | 207 } |
208 | 208 |
209 // This is the callback called from usrsctp when data has been received, after | 209 // This is the callback called from usrsctp when data has been received, after |
210 // a packet has been interpreted and parsed by usrsctp and found to contain | 210 // a packet has been interpreted and parsed by usrsctp and found to contain |
211 // payload data. It is called by a usrsctp thread. It is assumed this function | 211 // payload data. It is called by a usrsctp thread. It is assumed this function |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
308 } | 308 } |
309 | 309 |
310 DataMediaChannel* SctpDataEngine::CreateChannel( | 310 DataMediaChannel* SctpDataEngine::CreateChannel( |
311 DataChannelType data_channel_type) { | 311 DataChannelType data_channel_type) { |
312 if (data_channel_type != DCT_SCTP) { | 312 if (data_channel_type != DCT_SCTP) { |
313 return NULL; | 313 return NULL; |
314 } | 314 } |
315 return new SctpDataMediaChannel(rtc::Thread::Current()); | 315 return new SctpDataMediaChannel(rtc::Thread::Current()); |
316 } | 316 } |
317 | 317 |
318 // Our registrar of sockets to their channels. Used for callbacks. | |
319 SctpDataMediaChannel::SocketChannelMap SctpDataMediaChannel::sock_channel_map_; | |
320 | |
318 SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread) | 321 SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread) |
319 : worker_thread_(thread), | 322 : worker_thread_(thread), |
320 local_port_(kSctpDefaultPort), | 323 local_port_(kSctpDefaultPort), |
321 remote_port_(kSctpDefaultPort), | 324 remote_port_(kSctpDefaultPort), |
322 sock_(NULL), | 325 sock_(NULL), |
323 sending_(false), | 326 sending_(false), |
324 receiving_(false), | 327 receiving_(false), |
325 debug_name_("SctpDataMediaChannel") { | 328 debug_name_("SctpDataMediaChannel") { |
326 } | 329 } |
327 | 330 |
328 SctpDataMediaChannel::~SctpDataMediaChannel() { | 331 SctpDataMediaChannel::~SctpDataMediaChannel() { |
329 CloseSctpSocket(); | 332 CloseSctpSocket(); |
330 } | 333 } |
331 | 334 |
332 sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) { | 335 sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) { |
333 sockaddr_conn sconn = {0}; | 336 sockaddr_conn sconn = {0}; |
334 sconn.sconn_family = AF_CONN; | 337 sconn.sconn_family = AF_CONN; |
335 #ifdef HAVE_SCONN_LEN | 338 #ifdef HAVE_SCONN_LEN |
336 sconn.sconn_len = sizeof(sockaddr_conn); | 339 sconn.sconn_len = sizeof(sockaddr_conn); |
337 #endif | 340 #endif |
338 // Note: conversion from int to uint16_t happens here. | 341 // Note: conversion from int to uint16_t happens here. |
339 sconn.sconn_port = rtc::HostToNetwork16(port); | 342 sconn.sconn_port = rtc::HostToNetwork16(port); |
340 sconn.sconn_addr = this; | 343 sconn.sconn_addr = this; |
341 return sconn; | 344 return sconn; |
342 } | 345 } |
343 | 346 |
347 // static | |
348 int SctpDataMediaChannel::SendThresholdCallback(struct socket* sock, | |
pthatcher1
2015/08/05 21:42:55
I think it would make more sense to put this callb
lally1
2015/08/18 20:38:56
I don't know where I'd get an instance pointer.
pthatcher1
2015/08/18 21:51:52
The instance pointer to the engine? Could you use
| |
349 uint32_t sb_free) { | |
pthatcher1
2015/08/05 21:42:55
No ulp_info, like with reading a packet? That's l
lally1
2015/08/18 20:38:56
Yeah, that's the real issue here. I had a prior v
| |
350 SocketChannelMap::iterator it = sock_channel_map_.find(sock); | |
pthatcher1
2015/08/05 21:42:55
You can use
auto it = sock_channel_map_.find(soc
lally1
2015/08/18 20:38:56
Thanks!
| |
351 if (it == sock_channel_map_.end()) { | |
pthatcher1
2015/08/05 21:42:55
Since there are almost always a very low number of
lally1
2015/08/18 20:38:56
Done.
| |
352 // Socket is in the process of shutdown. | |
353 LOG(LS_ERROR) << "Failed to get SctpDataMediaChannel for socket " << sock; | |
354 return 0; | |
355 } | |
356 | |
357 it->second->SignalReadyToSend(true); | |
358 return 0; | |
359 } | |
360 | |
344 bool SctpDataMediaChannel::OpenSctpSocket() { | 361 bool SctpDataMediaChannel::OpenSctpSocket() { |
345 if (sock_) { | 362 if (sock_) { |
346 LOG(LS_VERBOSE) << debug_name_ | 363 LOG(LS_VERBOSE) << debug_name_ |
347 << "->Ignoring attempt to re-create existing socket."; | 364 << "->Ignoring attempt to re-create existing socket."; |
348 return false; | 365 return false; |
349 } | 366 } |
367 | |
368 const int send_threshold = usrsctp_sysctl_get_sctp_sendspace() / 2; | |
369 | |
350 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, | 370 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, |
351 cricket::OnSctpInboundPacket, NULL, 0, this); | 371 cricket::OnSctpInboundPacket, |
372 &SctpDataMediaChannel::SendThresholdCallback, | |
373 send_threshold, this); | |
352 if (!sock_) { | 374 if (!sock_) { |
353 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; | 375 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; |
354 return false; | 376 return false; |
355 } | 377 } |
356 | 378 |
379 sock_channel_map_[sock_] = this; | |
380 | |
357 // Make the socket non-blocking. Connect, close, shutdown etc will not block | 381 // Make the socket non-blocking. Connect, close, shutdown etc will not block |
358 // the thread waiting for the socket operation to complete. | 382 // the thread waiting for the socket operation to complete. |
359 if (usrsctp_set_non_blocking(sock_, 1) < 0) { | 383 if (usrsctp_set_non_blocking(sock_, 1) < 0) { |
360 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; | 384 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; |
361 return false; | 385 return false; |
362 } | 386 } |
363 | 387 |
364 // This ensures that the usrsctp close call deletes the association. This | 388 // This ensures that the usrsctp close call deletes the association. This |
365 // prevents usrsctp from calling OnSctpOutboundPacket with references to | 389 // prevents usrsctp from calling OnSctpOutboundPacket with references to |
366 // this class as the address. | 390 // this class as the address. |
(...skipping 19 matching lines...) Expand all Loading... | |
386 | 410 |
387 // Nagle. | 411 // Nagle. |
388 uint32_t nodelay = 1; | 412 uint32_t nodelay = 1; |
389 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, | 413 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, |
390 sizeof(nodelay))) { | 414 sizeof(nodelay))) { |
391 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY."; | 415 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY."; |
392 return false; | 416 return false; |
393 } | 417 } |
394 | 418 |
395 // Disable MTU discovery | 419 // Disable MTU discovery |
396 struct sctp_paddrparams params = {{0}}; | 420 struct sctp_paddrparams params; |
421 memset(¶ms, 0, sizeof(params)); | |
397 params.spp_assoc_id = 0; | 422 params.spp_assoc_id = 0; |
398 params.spp_flags = SPP_PMTUD_DISABLE; | 423 params.spp_flags = SPP_PMTUD_DISABLE; |
399 params.spp_pathmtu = kSctpMtu; | 424 params.spp_pathmtu = kSctpMtu; |
400 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, | 425 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, |
401 sizeof(params))) { | 426 sizeof(params))) { |
402 LOG_ERRNO(LS_ERROR) << debug_name_ | 427 LOG_ERRNO(LS_ERROR) << debug_name_ |
403 << "Failed to set SCTP_PEER_ADDR_PARAMS."; | 428 << "Failed to set SCTP_PEER_ADDR_PARAMS."; |
404 return false; | 429 return false; |
405 } | 430 } |
406 | 431 |
(...skipping 23 matching lines...) Expand all Loading... | |
430 return true; | 455 return true; |
431 } | 456 } |
432 | 457 |
433 void SctpDataMediaChannel::CloseSctpSocket() { | 458 void SctpDataMediaChannel::CloseSctpSocket() { |
434 sending_ = false; | 459 sending_ = false; |
435 if (sock_) { | 460 if (sock_) { |
436 // We assume that SO_LINGER option is set to close the association when | 461 // We assume that SO_LINGER option is set to close the association when |
437 // close is called. This means that any pending packets in usrsctp will be | 462 // close is called. This means that any pending packets in usrsctp will be |
438 // discarded instead of being sent. | 463 // discarded instead of being sent. |
439 usrsctp_close(sock_); | 464 usrsctp_close(sock_); |
465 SocketChannelMap::iterator it = sock_channel_map_.find(sock_); | |
466 if (it != sock_channel_map_.end()) { | |
467 sock_channel_map_.erase(it); | |
468 } else { | |
469 LOG(LS_ERROR) << "CloseSctpSocket: the socket wasn't registered."; | |
470 } | |
pthatcher1
2015/08/05 21:42:55
I think this works, and it shorter and only does o
lally1
2015/08/18 20:38:56
Thanks. Moved above into ~SctpDataMediaChannel(),
| |
440 sock_ = NULL; | 471 sock_ = NULL; |
441 usrsctp_deregister_address(this); | 472 usrsctp_deregister_address(this); |
442 } | 473 } |
443 } | 474 } |
444 | 475 |
445 bool SctpDataMediaChannel::Connect() { | 476 bool SctpDataMediaChannel::Connect() { |
446 LOG(LS_VERBOSE) << debug_name_ << "->Connect()."; | 477 LOG(LS_VERBOSE) << debug_name_ << "->Connect()."; |
447 | 478 |
448 // If we already have a socket connection, just return. | 479 // If we already have a socket connection, just return. |
449 if (sock_) { | 480 if (sock_) { |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
897 } | 928 } |
898 | 929 |
899 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { | 930 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { |
900 return GetCodecIntParameter( | 931 return GetCodecIntParameter( |
901 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort, | 932 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort, |
902 &local_port_); | 933 &local_port_); |
903 } | 934 } |
904 | 935 |
905 void SctpDataMediaChannel::OnPacketFromSctpToNetwork( | 936 void SctpDataMediaChannel::OnPacketFromSctpToNetwork( |
906 rtc::Buffer* buffer) { | 937 rtc::Buffer* buffer) { |
907 if (buffer->size() > kSctpMtu) { | 938 // this is completely made up. |
939 const int kSctpOverhead = 76; | |
pthatcher1
2015/08/05 21:42:55
This could use a little more documentation, even i
lally1
2015/08/18 20:38:56
Done.
| |
940 if (buffer->size() > (kSctpOverhead + kSctpMtu)) { | |
908 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): " | 941 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): " |
909 << "SCTP seems to have made a packet that is bigger " | 942 << "SCTP seems to have made a packet that is bigger " |
910 "than its official MTU."; | 943 << "than its official MTU: " << buffer->size() |
944 << " vs max of " << kSctpMtu; | |
pthatcher1
2015/08/05 21:42:55
Should probably include something like "assuming X
lally1
2015/08/18 20:38:56
Done.
| |
911 } | 945 } |
912 MediaChannel::SendPacket(buffer); | 946 MediaChannel::SendPacket(buffer); |
913 } | 947 } |
914 | 948 |
915 bool SctpDataMediaChannel::SendQueuedStreamResets() { | 949 bool SctpDataMediaChannel::SendQueuedStreamResets() { |
916 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) | 950 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) |
917 return true; | 951 return true; |
918 | 952 |
919 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending [" | 953 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending [" |
920 << ListStreams(queued_reset_streams_) << "], Open: [" | 954 << ListStreams(queued_reset_streams_) << "], Open: [" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
962 } | 996 } |
963 case MSG_SCTPOUTBOUNDPACKET: { | 997 case MSG_SCTPOUTBOUNDPACKET: { |
964 rtc::scoped_ptr<OutboundPacketMessage> pdata( | 998 rtc::scoped_ptr<OutboundPacketMessage> pdata( |
965 static_cast<OutboundPacketMessage*>(msg->pdata)); | 999 static_cast<OutboundPacketMessage*>(msg->pdata)); |
966 OnPacketFromSctpToNetwork(pdata->data().get()); | 1000 OnPacketFromSctpToNetwork(pdata->data().get()); |
967 break; | 1001 break; |
968 } | 1002 } |
969 } | 1003 } |
970 } | 1004 } |
971 } // namespace cricket | 1005 } // namespace cricket |
OLD | NEW |