github.com/pion/webrtc/v4@v4.0.1/datachannel.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 //go:build !js 5 // +build !js 6 7 package webrtc 8 9 import ( 10 "errors" 11 "fmt" 12 "io" 13 "math" 14 "sync" 15 "sync/atomic" 16 "time" 17 18 "github.com/pion/datachannel" 19 "github.com/pion/logging" 20 "github.com/pion/webrtc/v4/pkg/rtcerr" 21 ) 22 23 const dataChannelBufferSize = math.MaxUint16 // message size limit for Chromium 24 var errSCTPNotEstablished = errors.New("SCTP not established") 25 26 // DataChannel represents a WebRTC DataChannel 27 // The DataChannel interface represents a network channel 28 // which can be used for bidirectional peer-to-peer transfers of arbitrary data 29 type DataChannel struct { 30 mu sync.RWMutex 31 32 statsID string 33 label string 34 ordered bool 35 maxPacketLifeTime *uint16 36 maxRetransmits *uint16 37 protocol string 38 negotiated bool 39 id *uint16 40 readyState atomic.Value // DataChannelState 41 bufferedAmountLowThreshold uint64 42 detachCalled bool 43 readLoopActive chan struct{} 44 isGracefulClosed bool 45 46 // The binaryType represents attribute MUST, on getting, return the value to 47 // which it was last set. On setting, if the new value is either the string 48 // "blob" or the string "arraybuffer", then set the IDL attribute to this 49 // new value. Otherwise, throw a SyntaxError. When an DataChannel object 50 // is created, the binaryType attribute MUST be initialized to the string 51 // "blob". This attribute controls how binary data is exposed to scripts. 52 // binaryType string 53 54 onMessageHandler func(DataChannelMessage) 55 openHandlerOnce sync.Once 56 onOpenHandler func() 57 dialHandlerOnce sync.Once 58 onDialHandler func() 59 onCloseHandler func() 60 onBufferedAmountLow func() 61 onErrorHandler func(error) 62 63 sctpTransport *SCTPTransport 64 dataChannel *datachannel.DataChannel 65 66 // A reference to the associated api object used by this datachannel 67 api *API 68 log logging.LeveledLogger 69 } 70 71 // NewDataChannel creates a new DataChannel. 72 // This constructor is part of the ORTC API. It is not 73 // meant to be used together with the basic WebRTC API. 74 func (api *API) NewDataChannel(transport *SCTPTransport, params *DataChannelParameters) (*DataChannel, error) { 75 d, err := api.newDataChannel(params, nil, api.settingEngine.LoggerFactory.NewLogger("ortc")) 76 if err != nil { 77 return nil, err 78 } 79 80 err = d.open(transport) 81 if err != nil { 82 return nil, err 83 } 84 85 return d, nil 86 } 87 88 // newDataChannel is an internal constructor for the data channel used to 89 // create the DataChannel object before the networking is set up. 90 func (api *API) newDataChannel(params *DataChannelParameters, sctpTransport *SCTPTransport, log logging.LeveledLogger) (*DataChannel, error) { 91 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #5) 92 if len(params.Label) > 65535 { 93 return nil, &rtcerr.TypeError{Err: ErrStringSizeLimit} 94 } 95 96 d := &DataChannel{ 97 sctpTransport: sctpTransport, 98 statsID: fmt.Sprintf("DataChannel-%d", time.Now().UnixNano()), 99 label: params.Label, 100 protocol: params.Protocol, 101 negotiated: params.Negotiated, 102 id: params.ID, 103 ordered: params.Ordered, 104 maxPacketLifeTime: params.MaxPacketLifeTime, 105 maxRetransmits: params.MaxRetransmits, 106 api: api, 107 log: log, 108 } 109 110 d.setReadyState(DataChannelStateConnecting) 111 return d, nil 112 } 113 114 // open opens the datachannel over the sctp transport 115 func (d *DataChannel) open(sctpTransport *SCTPTransport) error { 116 association := sctpTransport.association() 117 if association == nil { 118 return errSCTPNotEstablished 119 } 120 121 d.mu.Lock() 122 if d.sctpTransport != nil { // already open 123 d.mu.Unlock() 124 return nil 125 } 126 d.sctpTransport = sctpTransport 127 var channelType datachannel.ChannelType 128 var reliabilityParameter uint32 129 130 switch { 131 case d.maxPacketLifeTime == nil && d.maxRetransmits == nil: 132 if d.ordered { 133 channelType = datachannel.ChannelTypeReliable 134 } else { 135 channelType = datachannel.ChannelTypeReliableUnordered 136 } 137 138 case d.maxRetransmits != nil: 139 reliabilityParameter = uint32(*d.maxRetransmits) 140 if d.ordered { 141 channelType = datachannel.ChannelTypePartialReliableRexmit 142 } else { 143 channelType = datachannel.ChannelTypePartialReliableRexmitUnordered 144 } 145 default: 146 reliabilityParameter = uint32(*d.maxPacketLifeTime) 147 if d.ordered { 148 channelType = datachannel.ChannelTypePartialReliableTimed 149 } else { 150 channelType = datachannel.ChannelTypePartialReliableTimedUnordered 151 } 152 } 153 154 cfg := &datachannel.Config{ 155 ChannelType: channelType, 156 Priority: datachannel.ChannelPriorityNormal, 157 ReliabilityParameter: reliabilityParameter, 158 Label: d.label, 159 Protocol: d.protocol, 160 Negotiated: d.negotiated, 161 LoggerFactory: d.api.settingEngine.LoggerFactory, 162 } 163 164 if d.id == nil { 165 // avoid holding lock when generating ID, since id generation locks 166 d.mu.Unlock() 167 var dcID *uint16 168 err := d.sctpTransport.generateAndSetDataChannelID(d.sctpTransport.dtlsTransport.role(), &dcID) 169 if err != nil { 170 return err 171 } 172 d.mu.Lock() 173 d.id = dcID 174 } 175 dc, err := datachannel.Dial(association, *d.id, cfg) 176 if err != nil { 177 d.mu.Unlock() 178 return err 179 } 180 181 // bufferedAmountLowThreshold and onBufferedAmountLow might be set earlier 182 dc.SetBufferedAmountLowThreshold(d.bufferedAmountLowThreshold) 183 dc.OnBufferedAmountLow(d.onBufferedAmountLow) 184 d.mu.Unlock() 185 186 d.onDial() 187 d.handleOpen(dc, false, d.negotiated) 188 return nil 189 } 190 191 // Transport returns the SCTPTransport instance the DataChannel is sending over. 192 func (d *DataChannel) Transport() *SCTPTransport { 193 d.mu.RLock() 194 defer d.mu.RUnlock() 195 196 return d.sctpTransport 197 } 198 199 // After onOpen is complete check that the user called detach 200 // and provide an error message if the call was missed 201 func (d *DataChannel) checkDetachAfterOpen() { 202 d.mu.RLock() 203 defer d.mu.RUnlock() 204 205 if d.api.settingEngine.detach.DataChannels && !d.detachCalled { 206 d.log.Warn("webrtc.DetachDataChannels() enabled but didn't Detach, call Detach from OnOpen") 207 } 208 } 209 210 // OnOpen sets an event handler which is invoked when 211 // the underlying data transport has been established (or re-established). 212 func (d *DataChannel) OnOpen(f func()) { 213 d.mu.Lock() 214 d.openHandlerOnce = sync.Once{} 215 d.onOpenHandler = f 216 d.mu.Unlock() 217 218 if d.ReadyState() == DataChannelStateOpen { 219 // If the data channel is already open, call the handler immediately. 220 go d.openHandlerOnce.Do(func() { 221 f() 222 d.checkDetachAfterOpen() 223 }) 224 } 225 } 226 227 func (d *DataChannel) onOpen() { 228 d.mu.RLock() 229 handler := d.onOpenHandler 230 if d.isGracefulClosed { 231 d.mu.RUnlock() 232 return 233 } 234 d.mu.RUnlock() 235 236 if handler != nil { 237 go d.openHandlerOnce.Do(func() { 238 handler() 239 d.checkDetachAfterOpen() 240 }) 241 } 242 } 243 244 // OnDial sets an event handler which is invoked when the 245 // peer has been dialed, but before said peer has responded 246 func (d *DataChannel) OnDial(f func()) { 247 d.mu.Lock() 248 d.dialHandlerOnce = sync.Once{} 249 d.onDialHandler = f 250 d.mu.Unlock() 251 252 if d.ReadyState() == DataChannelStateOpen { 253 // If the data channel is already open, call the handler immediately. 254 go d.dialHandlerOnce.Do(f) 255 } 256 } 257 258 func (d *DataChannel) onDial() { 259 d.mu.RLock() 260 handler := d.onDialHandler 261 if d.isGracefulClosed { 262 d.mu.RUnlock() 263 return 264 } 265 d.mu.RUnlock() 266 267 if handler != nil { 268 go d.dialHandlerOnce.Do(handler) 269 } 270 } 271 272 // OnClose sets an event handler which is invoked when 273 // the underlying data transport has been closed. 274 // Note: Due to backwards compatibility, there is a chance that 275 // OnClose can be called, even if the GracefulClose is used. 276 // If this is the case for you, you can deregister OnClose 277 // prior to GracefulClose. 278 func (d *DataChannel) OnClose(f func()) { 279 d.mu.Lock() 280 defer d.mu.Unlock() 281 d.onCloseHandler = f 282 } 283 284 func (d *DataChannel) onClose() { 285 d.mu.RLock() 286 handler := d.onCloseHandler 287 d.mu.RUnlock() 288 289 if handler != nil { 290 go handler() 291 } 292 } 293 294 // OnMessage sets an event handler which is invoked on a binary 295 // message arrival over the sctp transport from a remote peer. 296 // OnMessage can currently receive messages up to 16384 bytes 297 // in size. Check out the detach API if you want to use larger 298 // message sizes. Note that browser support for larger messages 299 // is also limited. 300 func (d *DataChannel) OnMessage(f func(msg DataChannelMessage)) { 301 d.mu.Lock() 302 defer d.mu.Unlock() 303 d.onMessageHandler = f 304 } 305 306 func (d *DataChannel) onMessage(msg DataChannelMessage) { 307 d.mu.RLock() 308 handler := d.onMessageHandler 309 if d.isGracefulClosed { 310 d.mu.RUnlock() 311 return 312 } 313 d.mu.RUnlock() 314 315 if handler == nil { 316 return 317 } 318 handler(msg) 319 } 320 321 func (d *DataChannel) handleOpen(dc *datachannel.DataChannel, isRemote, isAlreadyNegotiated bool) { 322 d.mu.Lock() 323 if d.isGracefulClosed { 324 d.mu.Unlock() 325 return 326 } 327 d.dataChannel = dc 328 bufferedAmountLowThreshold := d.bufferedAmountLowThreshold 329 onBufferedAmountLow := d.onBufferedAmountLow 330 d.mu.Unlock() 331 d.setReadyState(DataChannelStateOpen) 332 333 // Fire the OnOpen handler immediately not using pion/datachannel 334 // * detached datachannels have no read loop, the user needs to read and query themselves 335 // * remote datachannels should fire OnOpened. This isn't spec compliant, but we can't break behavior yet 336 // * already negotiated datachannels should fire OnOpened 337 if d.api.settingEngine.detach.DataChannels || isRemote || isAlreadyNegotiated { 338 // bufferedAmountLowThreshold and onBufferedAmountLow might be set earlier 339 d.dataChannel.SetBufferedAmountLowThreshold(bufferedAmountLowThreshold) 340 d.dataChannel.OnBufferedAmountLow(onBufferedAmountLow) 341 d.onOpen() 342 } else { 343 dc.OnOpen(func() { 344 d.onOpen() 345 }) 346 } 347 348 d.mu.Lock() 349 defer d.mu.Unlock() 350 351 if d.isGracefulClosed { 352 return 353 } 354 355 if !d.api.settingEngine.detach.DataChannels { 356 d.readLoopActive = make(chan struct{}) 357 go d.readLoop() 358 } 359 } 360 361 // OnError sets an event handler which is invoked when 362 // the underlying data transport cannot be read. 363 func (d *DataChannel) OnError(f func(err error)) { 364 d.mu.Lock() 365 defer d.mu.Unlock() 366 d.onErrorHandler = f 367 } 368 369 func (d *DataChannel) onError(err error) { 370 d.mu.RLock() 371 handler := d.onErrorHandler 372 if d.isGracefulClosed { 373 d.mu.RUnlock() 374 return 375 } 376 d.mu.RUnlock() 377 378 if handler != nil { 379 go handler(err) 380 } 381 } 382 383 func (d *DataChannel) readLoop() { 384 defer func() { 385 d.mu.Lock() 386 readLoopActive := d.readLoopActive 387 d.mu.Unlock() 388 defer close(readLoopActive) 389 }() 390 buffer := make([]byte, dataChannelBufferSize) 391 for { 392 n, isString, err := d.dataChannel.ReadDataChannel(buffer) 393 if err != nil { 394 d.setReadyState(DataChannelStateClosed) 395 if !errors.Is(err, io.EOF) { 396 d.onError(err) 397 } 398 d.onClose() 399 return 400 } 401 402 m := DataChannelMessage{Data: make([]byte, n), IsString: isString} 403 copy(m.Data, buffer[:n]) 404 405 // NB: Why was DataChannelMessage not passed as a pointer value? 406 d.onMessage(m) // nolint:staticcheck 407 } 408 } 409 410 // Send sends the binary message to the DataChannel peer 411 func (d *DataChannel) Send(data []byte) error { 412 err := d.ensureOpen() 413 if err != nil { 414 return err 415 } 416 417 _, err = d.dataChannel.WriteDataChannel(data, false) 418 return err 419 } 420 421 // SendText sends the text message to the DataChannel peer 422 func (d *DataChannel) SendText(s string) error { 423 err := d.ensureOpen() 424 if err != nil { 425 return err 426 } 427 428 _, err = d.dataChannel.WriteDataChannel([]byte(s), true) 429 return err 430 } 431 432 func (d *DataChannel) ensureOpen() error { 433 d.mu.RLock() 434 defer d.mu.RUnlock() 435 if d.ReadyState() != DataChannelStateOpen { 436 return io.ErrClosedPipe 437 } 438 return nil 439 } 440 441 // Detach allows you to detach the underlying datachannel. This provides 442 // an idiomatic API to work with, however it disables the OnMessage callback. 443 // Before calling Detach you have to enable this behavior by calling 444 // webrtc.DetachDataChannels(). Combining detached and normal data channels 445 // is not supported. 446 // Please refer to the data-channels-detach example and the 447 // pion/datachannel documentation for the correct way to handle the 448 // resulting DataChannel object. 449 func (d *DataChannel) Detach() (datachannel.ReadWriteCloser, error) { 450 d.mu.Lock() 451 452 if !d.api.settingEngine.detach.DataChannels { 453 return nil, errDetachNotEnabled 454 } 455 456 if d.dataChannel == nil { 457 return nil, errDetachBeforeOpened 458 } 459 460 d.detachCalled = true 461 462 dataChannel := d.dataChannel 463 d.mu.Unlock() 464 465 // Remove the reference from SCTPTransport so that the datachannel 466 // can be garbage collected on close 467 d.sctpTransport.lock.Lock() 468 n := len(d.sctpTransport.dataChannels) 469 j := 0 470 for i := 0; i < n; i++ { 471 if d == d.sctpTransport.dataChannels[i] { 472 continue 473 } 474 d.sctpTransport.dataChannels[j] = d.sctpTransport.dataChannels[i] 475 j++ 476 } 477 for i := j; i < n; i++ { 478 d.sctpTransport.dataChannels[i] = nil 479 } 480 d.sctpTransport.dataChannels = d.sctpTransport.dataChannels[:j] 481 d.sctpTransport.lock.Unlock() 482 483 return dataChannel, nil 484 } 485 486 // Close Closes the DataChannel. It may be called regardless of whether 487 // the DataChannel object was created by this peer or the remote peer. 488 func (d *DataChannel) Close() error { 489 return d.close(false) 490 } 491 492 // GracefulClose Closes the DataChannel. It may be called regardless of whether 493 // the DataChannel object was created by this peer or the remote peer. It also waits 494 // for any goroutines it started to complete. This is only safe to call outside of 495 // DataChannel callbacks or if in a callback, in its own goroutine. 496 func (d *DataChannel) GracefulClose() error { 497 return d.close(true) 498 } 499 500 // Normally, close only stops writes from happening, so graceful=true 501 // will wait for reads to be finished based on underlying SCTP association 502 // closure or a SCTP reset stream from the other side. This is safe to call 503 // with graceful=true after tearing down a PeerConnection but not 504 // necessarily before. For example, if you used a vnet and dropped all packets 505 // right before closing the DataChannel, you'd need never see a reset stream. 506 func (d *DataChannel) close(shouldGracefullyClose bool) error { 507 d.mu.Lock() 508 d.isGracefulClosed = true 509 readLoopActive := d.readLoopActive 510 if shouldGracefullyClose && readLoopActive != nil { 511 defer func() { 512 <-readLoopActive 513 }() 514 } 515 haveSctpTransport := d.dataChannel != nil 516 d.mu.Unlock() 517 518 if d.ReadyState() == DataChannelStateClosed { 519 return nil 520 } 521 522 d.setReadyState(DataChannelStateClosing) 523 if !haveSctpTransport { 524 return nil 525 } 526 527 return d.dataChannel.Close() 528 } 529 530 // Label represents a label that can be used to distinguish this 531 // DataChannel object from other DataChannel objects. Scripts are 532 // allowed to create multiple DataChannel objects with the same label. 533 func (d *DataChannel) Label() string { 534 d.mu.RLock() 535 defer d.mu.RUnlock() 536 537 return d.label 538 } 539 540 // Ordered returns true if the DataChannel is ordered, and false if 541 // out-of-order delivery is allowed. 542 func (d *DataChannel) Ordered() bool { 543 d.mu.RLock() 544 defer d.mu.RUnlock() 545 546 return d.ordered 547 } 548 549 // MaxPacketLifeTime represents the length of the time window (msec) during 550 // which transmissions and retransmissions may occur in unreliable mode. 551 func (d *DataChannel) MaxPacketLifeTime() *uint16 { 552 d.mu.RLock() 553 defer d.mu.RUnlock() 554 555 return d.maxPacketLifeTime 556 } 557 558 // MaxRetransmits represents the maximum number of retransmissions that are 559 // attempted in unreliable mode. 560 func (d *DataChannel) MaxRetransmits() *uint16 { 561 d.mu.RLock() 562 defer d.mu.RUnlock() 563 564 return d.maxRetransmits 565 } 566 567 // Protocol represents the name of the sub-protocol used with this 568 // DataChannel. 569 func (d *DataChannel) Protocol() string { 570 d.mu.RLock() 571 defer d.mu.RUnlock() 572 573 return d.protocol 574 } 575 576 // Negotiated represents whether this DataChannel was negotiated by the 577 // application (true), or not (false). 578 func (d *DataChannel) Negotiated() bool { 579 d.mu.RLock() 580 defer d.mu.RUnlock() 581 582 return d.negotiated 583 } 584 585 // ID represents the ID for this DataChannel. The value is initially 586 // null, which is what will be returned if the ID was not provided at 587 // channel creation time, and the DTLS role of the SCTP transport has not 588 // yet been negotiated. Otherwise, it will return the ID that was either 589 // selected by the script or generated. After the ID is set to a non-null 590 // value, it will not change. 591 func (d *DataChannel) ID() *uint16 { 592 d.mu.RLock() 593 defer d.mu.RUnlock() 594 595 return d.id 596 } 597 598 // ReadyState represents the state of the DataChannel object. 599 func (d *DataChannel) ReadyState() DataChannelState { 600 if v, ok := d.readyState.Load().(DataChannelState); ok { 601 return v 602 } 603 return DataChannelState(0) 604 } 605 606 // BufferedAmount represents the number of bytes of application data 607 // (UTF-8 text and binary data) that have been queued using send(). Even 608 // though the data transmission can occur in parallel, the returned value 609 // MUST NOT be decreased before the current task yielded back to the event 610 // loop to prevent race conditions. The value does not include framing 611 // overhead incurred by the protocol, or buffering done by the operating 612 // system or network hardware. The value of BufferedAmount slot will only 613 // increase with each call to the send() method as long as the ReadyState is 614 // open; however, BufferedAmount does not reset to zero once the channel 615 // closes. 616 func (d *DataChannel) BufferedAmount() uint64 { 617 d.mu.RLock() 618 defer d.mu.RUnlock() 619 620 if d.dataChannel == nil { 621 return 0 622 } 623 return d.dataChannel.BufferedAmount() 624 } 625 626 // BufferedAmountLowThreshold represents the threshold at which the 627 // bufferedAmount is considered to be low. When the bufferedAmount decreases 628 // from above this threshold to equal or below it, the bufferedamountlow 629 // event fires. BufferedAmountLowThreshold is initially zero on each new 630 // DataChannel, but the application may change its value at any time. 631 // The threshold is set to 0 by default. 632 func (d *DataChannel) BufferedAmountLowThreshold() uint64 { 633 d.mu.RLock() 634 defer d.mu.RUnlock() 635 636 if d.dataChannel == nil { 637 return d.bufferedAmountLowThreshold 638 } 639 return d.dataChannel.BufferedAmountLowThreshold() 640 } 641 642 // SetBufferedAmountLowThreshold is used to update the threshold. 643 // See BufferedAmountLowThreshold(). 644 func (d *DataChannel) SetBufferedAmountLowThreshold(th uint64) { 645 d.mu.Lock() 646 defer d.mu.Unlock() 647 648 d.bufferedAmountLowThreshold = th 649 650 if d.dataChannel != nil { 651 d.dataChannel.SetBufferedAmountLowThreshold(th) 652 } 653 } 654 655 // OnBufferedAmountLow sets an event handler which is invoked when 656 // the number of bytes of outgoing data becomes lower than or equal to the 657 // BufferedAmountLowThreshold. 658 func (d *DataChannel) OnBufferedAmountLow(f func()) { 659 d.mu.Lock() 660 defer d.mu.Unlock() 661 662 d.onBufferedAmountLow = f 663 if d.dataChannel != nil { 664 d.dataChannel.OnBufferedAmountLow(f) 665 } 666 } 667 668 func (d *DataChannel) getStatsID() string { 669 d.mu.Lock() 670 defer d.mu.Unlock() 671 return d.statsID 672 } 673 674 func (d *DataChannel) collectStats(collector *statsReportCollector) { 675 collector.Collecting() 676 677 d.mu.Lock() 678 defer d.mu.Unlock() 679 680 stats := DataChannelStats{ 681 Timestamp: statsTimestampNow(), 682 Type: StatsTypeDataChannel, 683 ID: d.statsID, 684 Label: d.label, 685 Protocol: d.protocol, 686 // TransportID string `json:"transportId"` 687 State: d.ReadyState(), 688 } 689 690 if d.id != nil { 691 stats.DataChannelIdentifier = int32(*d.id) 692 } 693 694 if d.dataChannel != nil { 695 stats.MessagesSent = d.dataChannel.MessagesSent() 696 stats.BytesSent = d.dataChannel.BytesSent() 697 stats.MessagesReceived = d.dataChannel.MessagesReceived() 698 stats.BytesReceived = d.dataChannel.BytesReceived() 699 } 700 701 collector.Collect(stats.ID, stats) 702 } 703 704 func (d *DataChannel) setReadyState(r DataChannelState) { 705 d.readyState.Store(r) 706 }