github.com/eagleql/xray-core@v1.4.4/common/mux/writer.go (about)

     1  package mux
     2  
     3  import (
     4  	"github.com/eagleql/xray-core/common"
     5  	"github.com/eagleql/xray-core/common/buf"
     6  	"github.com/eagleql/xray-core/common/net"
     7  	"github.com/eagleql/xray-core/common/protocol"
     8  	"github.com/eagleql/xray-core/common/serial"
     9  )
    10  
    11  type Writer struct {
    12  	dest         net.Destination
    13  	writer       buf.Writer
    14  	id           uint16
    15  	followup     bool
    16  	hasError     bool
    17  	transferType protocol.TransferType
    18  }
    19  
    20  func NewWriter(id uint16, dest net.Destination, writer buf.Writer, transferType protocol.TransferType) *Writer {
    21  	return &Writer{
    22  		id:           id,
    23  		dest:         dest,
    24  		writer:       writer,
    25  		followup:     false,
    26  		transferType: transferType,
    27  	}
    28  }
    29  
    30  func NewResponseWriter(id uint16, writer buf.Writer, transferType protocol.TransferType) *Writer {
    31  	return &Writer{
    32  		id:           id,
    33  		writer:       writer,
    34  		followup:     true,
    35  		transferType: transferType,
    36  	}
    37  }
    38  
    39  func (w *Writer) getNextFrameMeta() FrameMetadata {
    40  	meta := FrameMetadata{
    41  		SessionID: w.id,
    42  		Target:    w.dest,
    43  	}
    44  
    45  	if w.followup {
    46  		meta.SessionStatus = SessionStatusKeep
    47  	} else {
    48  		w.followup = true
    49  		meta.SessionStatus = SessionStatusNew
    50  	}
    51  
    52  	return meta
    53  }
    54  
    55  func (w *Writer) writeMetaOnly() error {
    56  	meta := w.getNextFrameMeta()
    57  	b := buf.New()
    58  	if err := meta.WriteTo(b); err != nil {
    59  		return err
    60  	}
    61  	return w.writer.WriteMultiBuffer(buf.MultiBuffer{b})
    62  }
    63  
    64  func writeMetaWithFrame(writer buf.Writer, meta FrameMetadata, data buf.MultiBuffer) error {
    65  	frame := buf.New()
    66  	if len(data) == 1 {
    67  		frame.UDP = data[0].UDP
    68  	}
    69  	if err := meta.WriteTo(frame); err != nil {
    70  		return err
    71  	}
    72  	if _, err := serial.WriteUint16(frame, uint16(data.Len())); err != nil {
    73  		return err
    74  	}
    75  
    76  	mb2 := make(buf.MultiBuffer, 0, len(data)+1)
    77  	mb2 = append(mb2, frame)
    78  	mb2 = append(mb2, data...)
    79  	return writer.WriteMultiBuffer(mb2)
    80  }
    81  
    82  func (w *Writer) writeData(mb buf.MultiBuffer) error {
    83  	meta := w.getNextFrameMeta()
    84  	meta.Option.Set(OptionData)
    85  
    86  	return writeMetaWithFrame(w.writer, meta, mb)
    87  }
    88  
    89  // WriteMultiBuffer implements buf.Writer.
    90  func (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {
    91  	defer buf.ReleaseMulti(mb)
    92  
    93  	if mb.IsEmpty() {
    94  		return w.writeMetaOnly()
    95  	}
    96  
    97  	for !mb.IsEmpty() {
    98  		var chunk buf.MultiBuffer
    99  		if w.transferType == protocol.TransferTypeStream {
   100  			mb, chunk = buf.SplitSize(mb, 8*1024)
   101  		} else {
   102  			mb2, b := buf.SplitFirst(mb)
   103  			mb = mb2
   104  			chunk = buf.MultiBuffer{b}
   105  		}
   106  		if err := w.writeData(chunk); err != nil {
   107  			return err
   108  		}
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  // Close implements common.Closable.
   115  func (w *Writer) Close() error {
   116  	meta := FrameMetadata{
   117  		SessionID:     w.id,
   118  		SessionStatus: SessionStatusEnd,
   119  	}
   120  	if w.hasError {
   121  		meta.Option.Set(OptionError)
   122  	}
   123  
   124  	frame := buf.New()
   125  	common.Must(meta.WriteTo(frame))
   126  
   127  	w.writer.WriteMultiBuffer(buf.MultiBuffer{frame})
   128  	return nil
   129  }