Просмотр исходного кода

Fix: add mutex to serialize concurrent tun.Device.Write calls

Rod Hynes 8 лет назад
Родитель
Сommit
5ed4e2d010
1 измененных файлов с 17 добавлено и 2 удалено
  1. 17 2
      psiphon/common/tun/tun.go

+ 17 - 2
psiphon/common/tun/tun.go

@@ -2390,6 +2390,7 @@ packet debugging snippet:
 // preallocated buffers to avoid GC churn.
 type Device struct {
 	name           string
+	writeMutex     sync.Mutex
 	deviceIO       io.ReadWriteCloser
 	inboundBuffer  []byte
 	outboundBuffer []byte
@@ -2481,7 +2482,7 @@ func (device *Device) Name() string {
 // ReadPacket reads one full packet from the tun device. The
 // return value is a slice of a static, reused buffer, so the
 // value is only valid until the next ReadPacket call.
-// Concurrent calls to ReadPacket are not supported.
+// Concurrent calls to ReadPacket are _not_ supported.
 func (device *Device) ReadPacket() ([]byte, error) {
 
 	// readTunPacket performs the platform dependent
@@ -2495,9 +2496,23 @@ func (device *Device) ReadPacket() ([]byte, error) {
 }
 
 // WritePacket writes one full packet to the tun device.
-// Concurrent calls to WritePacket are not supported.
+// Concurrent calls to WritePacket are supported.
 func (device *Device) WritePacket(packet []byte) error {
 
+	// This mutex serves two purposes:
+	//
+	// - It ensures only one concurrent goroutine can use
+	//   outboundBuffer, for those platforms that use that
+	//   buffer when writing.
+	// - It ensures that only one concurrent goroutine will
+	//   reach the underlying blocking Write syscall;
+	//   concurrent callers should hold at the mutex and not
+	//   spawn an unbounded number of OS threads for the
+	//   syscall.
+
+	device.writeMutex.Lock()
+	defer device.writeMutex.Unlock()
+
 	// writeTunPacket performs the platform dependent
 	// packet write operation.
 	err := device.writeTunPacket(packet)