@@ -523,21 +523,106 @@ func (c *UDPConn) writeTo(raddr *net.UDPAddr, cm *ControlMessage, buffer []byte)
523
523
return c .packetConn .WriteTo (buffer , cm , raddr )
524
524
}
525
525
526
+ type UDPWriteCfg struct {
527
+ Ctx context.Context
528
+ RemoteAddr * net.UDPAddr
529
+ ControlMessage * ControlMessage
530
+ }
531
+
532
+ func (c * UDPWriteCfg ) ApplyWrite (cfg * UDPWriteCfg ) {
533
+ if c .Ctx != nil {
534
+ cfg .Ctx = c .Ctx
535
+ }
536
+ if c .RemoteAddr != nil {
537
+ cfg .RemoteAddr = c .RemoteAddr
538
+ }
539
+ if c .ControlMessage != nil {
540
+ cfg .ControlMessage = c .ControlMessage
541
+ }
542
+ }
543
+
544
+ type UDPWriteOption interface {
545
+ ApplyWrite (cfg * UDPWriteCfg )
546
+ }
547
+
548
+ type (
549
+ UDPWriteApplyFunc func (cfg * UDPWriteCfg )
550
+ UDPReadApplyFunc func (cfg * UDPReadCfg )
551
+ )
552
+
553
+ type ReadWriteOptionHandler [F UDPWriteApplyFunc | UDPReadApplyFunc ] struct {
554
+ Func F
555
+ }
556
+
557
+ func (o ReadWriteOptionHandler [F ]) ApplyWrite (cfg * UDPWriteCfg ) {
558
+ switch f := any (o .Func ).(type ) {
559
+ case UDPWriteApplyFunc :
560
+ f (cfg )
561
+ default :
562
+ panic (fmt .Errorf ("invalid option handler %T for UDP Write" , o .Func ))
563
+ }
564
+ }
565
+
566
+ func (o ReadWriteOptionHandler [F ]) ApplyRead (cfg * UDPReadCfg ) {
567
+ switch f := any (o .Func ).(type ) {
568
+ case UDPReadApplyFunc :
569
+ f (cfg )
570
+ default :
571
+ panic (fmt .Errorf ("invalid option handler %T for UDP Read" , o .Func ))
572
+ }
573
+ }
574
+
575
+ func writeOptionFunc (f UDPWriteApplyFunc ) ReadWriteOptionHandler [UDPWriteApplyFunc ] {
576
+ return ReadWriteOptionHandler [UDPWriteApplyFunc ]{
577
+ Func : f ,
578
+ }
579
+ }
580
+
581
+ type ContextOption struct {
582
+ Ctx context.Context
583
+ }
584
+
585
+ func (o ContextOption ) ApplyWrite (cfg * UDPWriteCfg ) {
586
+ cfg .Ctx = o .Ctx
587
+ }
588
+
589
+ // WithContext sets the context of operation.
590
+ func WithContext (ctx context.Context ) ContextOption {
591
+ return ContextOption {Ctx : ctx }
592
+ }
593
+
594
+ func (o ContextOption ) ApplyRead (cfg * UDPReadCfg ) {
595
+ cfg .Ctx = o .Ctx
596
+ }
597
+
598
+ // WithRemoteAddr sets the remote address to packet.
599
+ func WithRemoteAddr (raddr * net.UDPAddr ) UDPWriteOption {
600
+ return writeOptionFunc (func (cfg * UDPWriteCfg ) {
601
+ cfg .RemoteAddr = raddr
602
+ })
603
+ }
604
+
605
+ // WithControlMessage sets the control message to packet.
606
+ func WithControlMessage (cm * ControlMessage ) UDPWriteOption {
607
+ return writeOptionFunc (func (cfg * UDPWriteCfg ) {
608
+ cfg .ControlMessage = cm
609
+ })
610
+ }
611
+
526
612
// WriteWithContext writes data with context.
527
- func (c * UDPConn ) WriteWithContext ( ctx context. Context , raddr * net. UDPAddr , cm * ControlMessage , buffer []byte ) error {
528
- if raddr == nil {
613
+ func (c * UDPConn ) writeWithCfg ( buffer []byte , cfg UDPWriteCfg ) error {
614
+ if cfg . RemoteAddr == nil {
529
615
return fmt .Errorf ("cannot write with context: invalid raddr" )
530
616
}
531
-
532
617
select {
533
- case <- ctx .Done ():
534
- return ctx .Err ()
618
+ case <- cfg . Ctx .Done ():
619
+ return cfg . Ctx .Err ()
535
620
default :
536
621
}
537
622
if c .closed .Load () {
538
623
return ErrConnectionIsClosed
539
624
}
540
- n , err := c .writeTo (raddr , cm , buffer )
625
+ n , err := c .writeTo (cfg . RemoteAddr , cfg . ControlMessage , buffer )
541
626
if err != nil {
542
627
return err
543
628
}
@@ -548,24 +633,114 @@ func (c *UDPConn) WriteWithContext(ctx context.Context, raddr *net.UDPAddr, cm *
548
633
return nil
549
634
}
550
635
551
- // ReadWithContext reads packet with context.
552
- func (c * UDPConn ) ReadWithContext (ctx context.Context , buffer []byte ) (int , * ControlMessage , * net.UDPAddr , error ) {
636
+ // WriteWithOptions writes data with options. Via opts you can specify the remote address and control message.
637
+ func (c * UDPConn ) WriteWithOptions (buffer []byte , opts ... UDPWriteOption ) error {
638
+ cfg := UDPWriteCfg {
639
+ Ctx : context .Background (),
640
+ }
641
+ addr := c .RemoteAddr ()
642
+ if addr != nil {
643
+ if remoteAddr , ok := addr .(* net.UDPAddr ); ok {
644
+ cfg .RemoteAddr = remoteAddr
645
+ }
646
+ }
647
+ for _ , o := range opts {
648
+ o .ApplyWrite (& cfg )
649
+ }
650
+ return c .writeWithCfg (buffer , cfg )
651
+ }
652
+
653
+ // WriteWithContext writes data with context.
654
+ func (c * UDPConn ) WriteWithContext (ctx context.Context , raddr * net.UDPAddr , buffer []byte ) error {
655
+ return c .WriteWithOptions (buffer , WithContext (ctx ), WithRemoteAddr (raddr ))
656
+ }
657
+
658
+ type UDPReadCfg struct {
659
+ Ctx context.Context
660
+ RemoteAddr * * net.UDPAddr
661
+ ControlMessage * * ControlMessage
662
+ }
663
+
664
+ func (c * UDPReadCfg ) ApplyRead (cfg * UDPReadCfg ) {
665
+ if c .Ctx != nil {
666
+ cfg .Ctx = c .Ctx
667
+ }
668
+ if c .RemoteAddr != nil {
669
+ cfg .RemoteAddr = c .RemoteAddr
670
+ }
671
+ if c .ControlMessage != nil {
672
+ cfg .ControlMessage = c .ControlMessage
673
+ }
674
+ }
675
+
676
+ type UDPReadOption interface {
677
+ ApplyRead (cfg * UDPReadCfg )
678
+ }
679
+
680
+ func readOptionFunc (f UDPReadApplyFunc ) UDPReadOption {
681
+ return ReadWriteOptionHandler [UDPReadApplyFunc ]{
682
+ Func : f ,
683
+ }
684
+ }
685
+
686
+ // WithGetRemoteAddr fills the remote address when reading succeeds.
687
+ func WithGetRemoteAddr (raddr * * net.UDPAddr ) UDPReadOption {
688
+ return readOptionFunc (func (cfg * UDPReadCfg ) {
689
+ cfg .RemoteAddr = raddr
690
+ })
691
+ }
692
+
693
+ // WithGetControlMessage fills the control message when reading succeeds.
694
+ func WithGetControlMessage (cm * * ControlMessage ) UDPReadOption {
695
+ return readOptionFunc (func (cfg * UDPReadCfg ) {
696
+ cfg .ControlMessage = cm
697
+ })
698
+ }
699
+
700
+ func (c * UDPConn ) readWithCfg (buffer []byte , cfg UDPReadCfg ) (int , error ) {
553
701
select {
554
- case <- ctx .Done ():
555
- return - 1 , nil , nil , ctx .Err ()
702
+ case <- cfg . Ctx .Done ():
703
+ return - 1 , cfg . Ctx .Err ()
556
704
default :
557
705
}
558
706
if c .closed .Load () {
559
- return - 1 , nil , nil , ErrConnectionIsClosed
707
+ return - 1 , ErrConnectionIsClosed
560
708
}
561
709
n , cm , srcAddr , err := c .packetConn .ReadFrom (buffer )
562
710
if err != nil {
563
- return - 1 , nil , nil , fmt .Errorf ("cannot read from udp connection: %w" , err )
711
+ return - 1 , fmt .Errorf ("cannot read from udp connection: %w" , err )
564
712
}
565
713
if udpAdrr , ok := srcAddr .(* net.UDPAddr ); ok {
566
- return n , cm , udpAdrr , nil
714
+ if cfg .RemoteAddr != nil {
715
+ * cfg .RemoteAddr = udpAdrr
716
+ }
717
+ if cfg .ControlMessage != nil {
718
+ * cfg .ControlMessage = cm
719
+ }
720
+ return n , nil
721
+ }
722
+ return - 1 , fmt .Errorf ("cannot read from udp connection: invalid srcAddr type %T" , srcAddr )
723
+ }
724
+
725
+ // ReadWithOptions reads packet with options. Via opts you can get also the remote address and control message.
726
+ func (c * UDPConn ) ReadWithOptions (buffer []byte , opts ... UDPReadOption ) (int , error ) {
727
+ cfg := UDPReadCfg {
728
+ Ctx : context .Background (),
729
+ }
730
+ for _ , o := range opts {
731
+ o .ApplyRead (& cfg )
732
+ }
733
+ return c .readWithCfg (buffer , cfg )
734
+ }
735
+
736
+ // ReadWithContext reads packet with context.
737
+ func (c * UDPConn ) ReadWithContext (ctx context.Context , buffer []byte ) (int , * net.UDPAddr , error ) {
738
+ var remoteAddr * net.UDPAddr
739
+ n , err := c .ReadWithOptions (buffer , WithContext (ctx ), WithGetRemoteAddr (& remoteAddr ))
740
+ if err != nil {
741
+ return - 1 , nil , err
567
742
}
568
- return - 1 , nil , nil , fmt . Errorf ( "cannot read from udp connection: invalid srcAddr type %T" , srcAddr )
743
+ return n , remoteAddr , err
569
744
}
570
745
571
746
// SetMulticastLoopback sets whether transmitted multicast packets
0 commit comments