proxy.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. // Package proxy contains all proxies used by Xray.
  2. //
  3. // To implement an inbound or outbound proxy, one needs to do the following:
  4. // 1. Implement the interface(s) below.
  5. // 2. Register a config creator through common.RegisterConfig.
  6. package proxy
  7. import (
  8. "bytes"
  9. "context"
  10. "crypto/rand"
  11. "io"
  12. "math/big"
  13. "runtime"
  14. "strconv"
  15. "time"
  16. "github.com/pires/go-proxyproto"
  17. "github.com/xtls/xray-core/app/dispatcher"
  18. "github.com/xtls/xray-core/common/buf"
  19. "github.com/xtls/xray-core/common/errors"
  20. "github.com/xtls/xray-core/common/net"
  21. "github.com/xtls/xray-core/common/protocol"
  22. "github.com/xtls/xray-core/common/session"
  23. "github.com/xtls/xray-core/common/signal"
  24. "github.com/xtls/xray-core/features/routing"
  25. "github.com/xtls/xray-core/features/stats"
  26. "github.com/xtls/xray-core/transport"
  27. "github.com/xtls/xray-core/transport/internet"
  28. "github.com/xtls/xray-core/transport/internet/reality"
  29. "github.com/xtls/xray-core/transport/internet/stat"
  30. "github.com/xtls/xray-core/transport/internet/tls"
  31. )
  32. var (
  33. Tls13SupportedVersions = []byte{0x00, 0x2b, 0x00, 0x02, 0x03, 0x04}
  34. TlsClientHandShakeStart = []byte{0x16, 0x03}
  35. TlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
  36. TlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
  37. Tls13CipherSuiteDic = map[uint16]string{
  38. 0x1301: "TLS_AES_128_GCM_SHA256",
  39. 0x1302: "TLS_AES_256_GCM_SHA384",
  40. 0x1303: "TLS_CHACHA20_POLY1305_SHA256",
  41. 0x1304: "TLS_AES_128_CCM_SHA256",
  42. 0x1305: "TLS_AES_128_CCM_8_SHA256",
  43. }
  44. )
  45. const (
  46. TlsHandshakeTypeClientHello byte = 0x01
  47. TlsHandshakeTypeServerHello byte = 0x02
  48. CommandPaddingContinue byte = 0x00
  49. CommandPaddingEnd byte = 0x01
  50. CommandPaddingDirect byte = 0x02
  51. )
  52. // An Inbound processes inbound connections.
  53. type Inbound interface {
  54. // Network returns a list of networks that this inbound supports. Connections with not-supported networks will not be passed into Process().
  55. Network() []net.Network
  56. // Process processes a connection of given network. If necessary, the Inbound can dispatch the connection to an Outbound.
  57. Process(context.Context, net.Network, stat.Connection, routing.Dispatcher) error
  58. }
  59. // An Outbound process outbound connections.
  60. type Outbound interface {
  61. // Process processes the given connection. The given dialer may be used to dial a system outbound connection.
  62. Process(context.Context, *transport.Link, internet.Dialer) error
  63. }
  64. // UserManager is the interface for Inbounds and Outbounds that can manage their users.
  65. type UserManager interface {
  66. // AddUser adds a new user.
  67. AddUser(context.Context, *protocol.MemoryUser) error
  68. // RemoveUser removes a user by email.
  69. RemoveUser(context.Context, string) error
  70. // Get user by email.
  71. GetUser(context.Context, string) *protocol.MemoryUser
  72. // Get all users.
  73. GetUsers(context.Context) []*protocol.MemoryUser
  74. // Get users count.
  75. GetUsersCount(context.Context) int64
  76. }
  77. type GetInbound interface {
  78. GetInbound() Inbound
  79. }
  80. type GetOutbound interface {
  81. GetOutbound() Outbound
  82. }
  83. // TrafficState is used to track uplink and downlink of one connection
  84. // It is used by XTLS to determine if switch to raw copy mode, It is used by Vision to calculate padding
  85. type TrafficState struct {
  86. UserUUID []byte
  87. NumberOfPacketToFilter int
  88. EnableXtls bool
  89. IsTLS12orAbove bool
  90. IsTLS bool
  91. Cipher uint16
  92. RemainingServerHello int32
  93. // reader link state
  94. WithinPaddingBuffers bool
  95. DownlinkReaderDirectCopy bool
  96. UplinkReaderDirectCopy bool
  97. RemainingCommand int32
  98. RemainingContent int32
  99. RemainingPadding int32
  100. CurrentCommand int
  101. // write link state
  102. IsPadding bool
  103. DownlinkWriterDirectCopy bool
  104. UplinkWriterDirectCopy bool
  105. }
  106. func NewTrafficState(userUUID []byte) *TrafficState {
  107. return &TrafficState{
  108. UserUUID: userUUID,
  109. NumberOfPacketToFilter: 8,
  110. EnableXtls: false,
  111. IsTLS12orAbove: false,
  112. IsTLS: false,
  113. Cipher: 0,
  114. RemainingServerHello: -1,
  115. WithinPaddingBuffers: true,
  116. DownlinkReaderDirectCopy: false,
  117. UplinkReaderDirectCopy: false,
  118. RemainingCommand: -1,
  119. RemainingContent: -1,
  120. RemainingPadding: -1,
  121. CurrentCommand: 0,
  122. IsPadding: true,
  123. DownlinkWriterDirectCopy: false,
  124. UplinkWriterDirectCopy: false,
  125. }
  126. }
  127. // VisionReader is used to read xtls vision protocol
  128. // Note Vision probably only make sense as the inner most layer of reader, since it need assess traffic state from origin proxy traffic
  129. type VisionReader struct {
  130. buf.Reader
  131. trafficState *TrafficState
  132. ctx context.Context
  133. isUplink bool
  134. }
  135. func NewVisionReader(reader buf.Reader, state *TrafficState, isUplink bool, context context.Context) *VisionReader {
  136. return &VisionReader{
  137. Reader: reader,
  138. trafficState: state,
  139. ctx: context,
  140. isUplink: isUplink,
  141. }
  142. }
  143. func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
  144. buffer, err := w.Reader.ReadMultiBuffer()
  145. if !buffer.IsEmpty() {
  146. if w.trafficState.WithinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
  147. mb2 := make(buf.MultiBuffer, 0, len(buffer))
  148. for _, b := range buffer {
  149. newbuffer := XtlsUnpadding(b, w.trafficState, w.ctx)
  150. if newbuffer.Len() > 0 {
  151. mb2 = append(mb2, newbuffer)
  152. }
  153. }
  154. buffer = mb2
  155. if w.trafficState.RemainingContent > 0 || w.trafficState.RemainingPadding > 0 || w.trafficState.CurrentCommand == 0 {
  156. w.trafficState.WithinPaddingBuffers = true
  157. } else if w.trafficState.CurrentCommand == 1 {
  158. w.trafficState.WithinPaddingBuffers = false
  159. } else if w.trafficState.CurrentCommand == 2 {
  160. w.trafficState.WithinPaddingBuffers = false
  161. if w.isUplink {
  162. w.trafficState.UplinkReaderDirectCopy = true
  163. } else {
  164. w.trafficState.DownlinkReaderDirectCopy = true
  165. }
  166. } else {
  167. errors.LogInfo(w.ctx, "XtlsRead unknown command ", w.trafficState.CurrentCommand, buffer.Len())
  168. }
  169. }
  170. if w.trafficState.NumberOfPacketToFilter > 0 {
  171. XtlsFilterTls(buffer, w.trafficState, w.ctx)
  172. }
  173. }
  174. return buffer, err
  175. }
  176. // VisionWriter is used to write xtls vision protocol
  177. // Note Vision probably only make sense as the inner most layer of writer, since it need assess traffic state from origin proxy traffic
  178. type VisionWriter struct {
  179. buf.Writer
  180. trafficState *TrafficState
  181. ctx context.Context
  182. writeOnceUserUUID []byte
  183. isUplink bool
  184. }
  185. func NewVisionWriter(writer buf.Writer, state *TrafficState, isUplink bool, context context.Context) *VisionWriter {
  186. w := make([]byte, len(state.UserUUID))
  187. copy(w, state.UserUUID)
  188. return &VisionWriter{
  189. Writer: writer,
  190. trafficState: state,
  191. ctx: context,
  192. writeOnceUserUUID: w,
  193. isUplink: isUplink,
  194. }
  195. }
  196. func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
  197. if w.trafficState.NumberOfPacketToFilter > 0 {
  198. XtlsFilterTls(mb, w.trafficState, w.ctx)
  199. }
  200. if w.trafficState.IsPadding {
  201. if len(mb) == 1 && mb[0] == nil {
  202. mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx) // we do a long padding to hide vless header
  203. return w.Writer.WriteMultiBuffer(mb)
  204. }
  205. mb = ReshapeMultiBuffer(w.ctx, mb)
  206. longPadding := w.trafficState.IsTLS
  207. for i, b := range mb {
  208. if w.trafficState.IsTLS && b.Len() >= 6 && bytes.Equal(TlsApplicationDataStart, b.BytesTo(3)) {
  209. if w.trafficState.EnableXtls {
  210. if w.isUplink {
  211. w.trafficState.UplinkWriterDirectCopy = true
  212. } else {
  213. w.trafficState.DownlinkWriterDirectCopy = true
  214. }
  215. }
  216. var command byte = CommandPaddingContinue
  217. if i == len(mb)-1 {
  218. command = CommandPaddingEnd
  219. if w.trafficState.EnableXtls {
  220. command = CommandPaddingDirect
  221. }
  222. }
  223. mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx)
  224. w.trafficState.IsPadding = false // padding going to end
  225. longPadding = false
  226. continue
  227. } else if !w.trafficState.IsTLS12orAbove && w.trafficState.NumberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
  228. w.trafficState.IsPadding = false
  229. mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx)
  230. break
  231. }
  232. var command byte = CommandPaddingContinue
  233. if i == len(mb)-1 && !w.trafficState.IsPadding {
  234. command = CommandPaddingEnd
  235. if w.trafficState.EnableXtls {
  236. command = CommandPaddingDirect
  237. }
  238. }
  239. mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, longPadding, w.ctx)
  240. }
  241. }
  242. return w.Writer.WriteMultiBuffer(mb)
  243. }
  244. // ReshapeMultiBuffer prepare multi buffer for padding structure (max 21 bytes)
  245. func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBuffer {
  246. needReshape := 0
  247. for _, b := range buffer {
  248. if b.Len() >= buf.Size-21 {
  249. needReshape += 1
  250. }
  251. }
  252. if needReshape == 0 {
  253. return buffer
  254. }
  255. mb2 := make(buf.MultiBuffer, 0, len(buffer)+needReshape)
  256. toPrint := ""
  257. for i, buffer1 := range buffer {
  258. if buffer1.Len() >= buf.Size-21 {
  259. index := int32(bytes.LastIndex(buffer1.Bytes(), TlsApplicationDataStart))
  260. if index < 21 || index > buf.Size-21 {
  261. index = buf.Size / 2
  262. }
  263. buffer2 := buf.New()
  264. buffer2.Write(buffer1.BytesFrom(index))
  265. buffer1.Resize(0, index)
  266. mb2 = append(mb2, buffer1, buffer2)
  267. toPrint += " " + strconv.Itoa(int(buffer1.Len())) + " " + strconv.Itoa(int(buffer2.Len()))
  268. } else {
  269. mb2 = append(mb2, buffer1)
  270. toPrint += " " + strconv.Itoa(int(buffer1.Len()))
  271. }
  272. buffer[i] = nil
  273. }
  274. buffer = buffer[:0]
  275. errors.LogInfo(ctx, "ReshapeMultiBuffer ", toPrint)
  276. return mb2
  277. }
  278. // XtlsPadding add padding to eliminate length signature during tls handshake
  279. func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer {
  280. var contentLen int32 = 0
  281. var paddingLen int32 = 0
  282. if b != nil {
  283. contentLen = b.Len()
  284. }
  285. if contentLen < 900 && longPadding {
  286. l, err := rand.Int(rand.Reader, big.NewInt(500))
  287. if err != nil {
  288. errors.LogDebugInner(ctx, err, "failed to generate padding")
  289. }
  290. paddingLen = int32(l.Int64()) + 900 - contentLen
  291. } else {
  292. l, err := rand.Int(rand.Reader, big.NewInt(256))
  293. if err != nil {
  294. errors.LogDebugInner(ctx, err, "failed to generate padding")
  295. }
  296. paddingLen = int32(l.Int64())
  297. }
  298. if paddingLen > buf.Size-21-contentLen {
  299. paddingLen = buf.Size - 21 - contentLen
  300. }
  301. newbuffer := buf.New()
  302. if userUUID != nil {
  303. newbuffer.Write(*userUUID)
  304. *userUUID = nil
  305. }
  306. newbuffer.Write([]byte{command, byte(contentLen >> 8), byte(contentLen), byte(paddingLen >> 8), byte(paddingLen)})
  307. if b != nil {
  308. newbuffer.Write(b.Bytes())
  309. b.Release()
  310. b = nil
  311. }
  312. newbuffer.Extend(paddingLen)
  313. errors.LogInfo(ctx, "XtlsPadding ", contentLen, " ", paddingLen, " ", command)
  314. return newbuffer
  315. }
  316. // XtlsUnpadding remove padding and parse command
  317. func XtlsUnpadding(b *buf.Buffer, s *TrafficState, ctx context.Context) *buf.Buffer {
  318. if s.RemainingCommand == -1 && s.RemainingContent == -1 && s.RemainingPadding == -1 { // initial state
  319. if b.Len() >= 21 && bytes.Equal(s.UserUUID, b.BytesTo(16)) {
  320. b.Advance(16)
  321. s.RemainingCommand = 5
  322. } else {
  323. return b
  324. }
  325. }
  326. newbuffer := buf.New()
  327. for b.Len() > 0 {
  328. if s.RemainingCommand > 0 {
  329. data, err := b.ReadByte()
  330. if err != nil {
  331. return newbuffer
  332. }
  333. switch s.RemainingCommand {
  334. case 5:
  335. s.CurrentCommand = int(data)
  336. case 4:
  337. s.RemainingContent = int32(data) << 8
  338. case 3:
  339. s.RemainingContent = s.RemainingContent | int32(data)
  340. case 2:
  341. s.RemainingPadding = int32(data) << 8
  342. case 1:
  343. s.RemainingPadding = s.RemainingPadding | int32(data)
  344. errors.LogInfo(ctx, "Xtls Unpadding new block, content ", s.RemainingContent, " padding ", s.RemainingPadding, " command ", s.CurrentCommand)
  345. }
  346. s.RemainingCommand--
  347. } else if s.RemainingContent > 0 {
  348. len := s.RemainingContent
  349. if b.Len() < len {
  350. len = b.Len()
  351. }
  352. data, err := b.ReadBytes(len)
  353. if err != nil {
  354. return newbuffer
  355. }
  356. newbuffer.Write(data)
  357. s.RemainingContent -= len
  358. } else { // remainingPadding > 0
  359. len := s.RemainingPadding
  360. if b.Len() < len {
  361. len = b.Len()
  362. }
  363. b.Advance(len)
  364. s.RemainingPadding -= len
  365. }
  366. if s.RemainingCommand <= 0 && s.RemainingContent <= 0 && s.RemainingPadding <= 0 { // this block done
  367. if s.CurrentCommand == 0 {
  368. s.RemainingCommand = 5
  369. } else {
  370. s.RemainingCommand = -1 // set to initial state
  371. s.RemainingContent = -1
  372. s.RemainingPadding = -1
  373. if b.Len() > 0 { // shouldn't happen
  374. newbuffer.Write(b.Bytes())
  375. }
  376. break
  377. }
  378. }
  379. }
  380. b.Release()
  381. b = nil
  382. return newbuffer
  383. }
  384. // XtlsFilterTls filter and recognize tls 1.3 and other info
  385. func XtlsFilterTls(buffer buf.MultiBuffer, trafficState *TrafficState, ctx context.Context) {
  386. for _, b := range buffer {
  387. if b == nil {
  388. continue
  389. }
  390. trafficState.NumberOfPacketToFilter--
  391. if b.Len() >= 6 {
  392. startsBytes := b.BytesTo(6)
  393. if bytes.Equal(TlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == TlsHandshakeTypeServerHello {
  394. trafficState.RemainingServerHello = (int32(startsBytes[3])<<8 | int32(startsBytes[4])) + 5
  395. trafficState.IsTLS12orAbove = true
  396. trafficState.IsTLS = true
  397. if b.Len() >= 79 && trafficState.RemainingServerHello >= 79 {
  398. sessionIdLen := int32(b.Byte(43))
  399. cipherSuite := b.BytesRange(43+sessionIdLen+1, 43+sessionIdLen+3)
  400. trafficState.Cipher = uint16(cipherSuite[0])<<8 | uint16(cipherSuite[1])
  401. } else {
  402. errors.LogInfo(ctx, "XtlsFilterTls short server hello, tls 1.2 or older? ", b.Len(), " ", trafficState.RemainingServerHello)
  403. }
  404. } else if bytes.Equal(TlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == TlsHandshakeTypeClientHello {
  405. trafficState.IsTLS = true
  406. errors.LogInfo(ctx, "XtlsFilterTls found tls client hello! ", buffer.Len())
  407. }
  408. }
  409. if trafficState.RemainingServerHello > 0 {
  410. end := trafficState.RemainingServerHello
  411. if end > b.Len() {
  412. end = b.Len()
  413. }
  414. trafficState.RemainingServerHello -= b.Len()
  415. if bytes.Contains(b.BytesTo(end), Tls13SupportedVersions) {
  416. v, ok := Tls13CipherSuiteDic[trafficState.Cipher]
  417. if !ok {
  418. v = "Old cipher: " + strconv.FormatUint(uint64(trafficState.Cipher), 16)
  419. } else if v != "TLS_AES_128_CCM_8_SHA256" {
  420. trafficState.EnableXtls = true
  421. }
  422. errors.LogInfo(ctx, "XtlsFilterTls found tls 1.3! ", b.Len(), " ", v)
  423. trafficState.NumberOfPacketToFilter = 0
  424. return
  425. } else if trafficState.RemainingServerHello <= 0 {
  426. errors.LogInfo(ctx, "XtlsFilterTls found tls 1.2! ", b.Len())
  427. trafficState.NumberOfPacketToFilter = 0
  428. return
  429. }
  430. errors.LogInfo(ctx, "XtlsFilterTls inconclusive server hello ", b.Len(), " ", trafficState.RemainingServerHello)
  431. }
  432. if trafficState.NumberOfPacketToFilter <= 0 {
  433. errors.LogInfo(ctx, "XtlsFilterTls stop filtering", buffer.Len())
  434. }
  435. }
  436. }
  437. // UnwrapRawConn support unwrap stats, tls, utls, reality and proxyproto conn and get raw tcp conn from it
  438. func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) {
  439. var readCounter, writerCounter stats.Counter
  440. if conn != nil {
  441. statConn, ok := conn.(*stat.CounterConnection)
  442. if ok {
  443. conn = statConn.Connection
  444. readCounter = statConn.ReadCounter
  445. writerCounter = statConn.WriteCounter
  446. }
  447. if xc, ok := conn.(*tls.Conn); ok {
  448. conn = xc.NetConn()
  449. } else if utlsConn, ok := conn.(*tls.UConn); ok {
  450. conn = utlsConn.NetConn()
  451. } else if realityConn, ok := conn.(*reality.Conn); ok {
  452. conn = realityConn.NetConn()
  453. } else if realityUConn, ok := conn.(*reality.UConn); ok {
  454. conn = realityUConn.NetConn()
  455. }
  456. if pc, ok := conn.(*proxyproto.Conn); ok {
  457. conn = pc.Raw()
  458. // 8192 > 4096, there is no need to process pc's bufReader
  459. }
  460. }
  461. return conn, readCounter, writerCounter
  462. }
  463. // CopyRawConnIfExist use the most efficient copy method.
  464. // - If caller don't want to turn on splice, do not pass in both reader conn and writer conn
  465. // - writer are from *transport.Link
  466. func CopyRawConnIfExist(ctx context.Context, readerConn net.Conn, writerConn net.Conn, writer buf.Writer, timer *signal.ActivityTimer, inTimer *signal.ActivityTimer) error {
  467. readerConn, readCounter, _ := UnwrapRawConn(readerConn)
  468. writerConn, _, writeCounter := UnwrapRawConn(writerConn)
  469. reader := buf.NewReader(readerConn)
  470. if runtime.GOOS != "linux" && runtime.GOOS != "android" {
  471. return readV(ctx, reader, writer, timer, readCounter)
  472. }
  473. tc, ok := writerConn.(*net.TCPConn)
  474. if !ok || readerConn == nil || writerConn == nil {
  475. return readV(ctx, reader, writer, timer, readCounter)
  476. }
  477. inbound := session.InboundFromContext(ctx)
  478. if inbound == nil || inbound.CanSpliceCopy == 3 {
  479. return readV(ctx, reader, writer, timer, readCounter)
  480. }
  481. outbounds := session.OutboundsFromContext(ctx)
  482. if len(outbounds) == 0 {
  483. return readV(ctx, reader, writer, timer, readCounter)
  484. }
  485. for _, ob := range outbounds {
  486. if ob.CanSpliceCopy == 3 {
  487. return readV(ctx, reader, writer, timer, readCounter)
  488. }
  489. }
  490. for {
  491. inbound := session.InboundFromContext(ctx)
  492. outbounds := session.OutboundsFromContext(ctx)
  493. var splice = inbound.CanSpliceCopy == 1
  494. for _, ob := range outbounds {
  495. if ob.CanSpliceCopy != 1 {
  496. splice = false
  497. }
  498. }
  499. if splice {
  500. errors.LogInfo(ctx, "CopyRawConn splice")
  501. statWriter, _ := writer.(*dispatcher.SizeStatWriter)
  502. //runtime.Gosched() // necessary
  503. time.Sleep(time.Millisecond) // without this, there will be a rare ssl error for freedom splice
  504. timer.SetTimeout(8 * time.Hour) // prevent leak, just in case
  505. if inTimer != nil {
  506. inTimer.SetTimeout(8 * time.Hour)
  507. }
  508. w, err := tc.ReadFrom(readerConn)
  509. if readCounter != nil {
  510. readCounter.Add(w) // outbound stats
  511. }
  512. if writeCounter != nil {
  513. writeCounter.Add(w) // inbound stats
  514. }
  515. if statWriter != nil {
  516. statWriter.Counter.Add(w) // user stats
  517. }
  518. if err != nil && errors.Cause(err) != io.EOF {
  519. return err
  520. }
  521. return nil
  522. }
  523. buffer, err := reader.ReadMultiBuffer()
  524. if !buffer.IsEmpty() {
  525. if readCounter != nil {
  526. readCounter.Add(int64(buffer.Len()))
  527. }
  528. timer.Update()
  529. if werr := writer.WriteMultiBuffer(buffer); werr != nil {
  530. return werr
  531. }
  532. }
  533. if err != nil {
  534. return err
  535. }
  536. }
  537. }
  538. func readV(ctx context.Context, reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, readCounter stats.Counter) error {
  539. errors.LogInfo(ctx, "CopyRawConn readv")
  540. if err := buf.Copy(reader, writer, buf.UpdateActivity(timer), buf.AddToStatCounter(readCounter)); err != nil {
  541. return errors.New("failed to process response").Base(err)
  542. }
  543. return nil
  544. }