go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/transport/ipc/ipc_unix_test.go (about)

     1  // Copyright 2020 The Mangos Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use file except in compliance with the License.
     5  // You may obtain a copy of the license at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // +build !plan9,!windows,!js
    16  
    17  package ipc
    18  
    19  import (
    20  	"errors"
    21  	"net"
    22  	"os"
    23  	"strings"
    24  	"syscall"
    25  	"testing"
    26  	"time"
    27  
    28  	"go.nanomsg.org/mangos/v3"
    29  	. "go.nanomsg.org/mangos/v3/internal/test"
    30  )
    31  
    32  func TestIsSyscallError(t *testing.T) {
    33  
    34  	MustBeFalse(t, isSyscallError(errors.New("nope"), syscall.ENOENT))
    35  	MustBeFalse(t, isSyscallError(&net.OpError{
    36  		Op:     "test",
    37  		Net:    "none",
    38  		Source: nil,
    39  		Addr:   nil,
    40  		Err:    mangos.ErrClosed,
    41  	}, syscall.ENOENT))
    42  	MustBeFalse(t, isSyscallError(&net.OpError{
    43  		Op:     "test",
    44  		Net:    "none",
    45  		Source: nil,
    46  		Addr:   nil,
    47  		Err: &os.SyscallError{
    48  			Syscall: "none",
    49  			Err:     syscall.EINVAL,
    50  		},
    51  	}, syscall.ENOENT))
    52  	MustBeFalse(t, isSyscallError(&net.OpError{
    53  		Op:     "test",
    54  		Net:    "none",
    55  		Source: nil,
    56  		Addr:   nil,
    57  		Err: &os.SyscallError{
    58  			Syscall: "none",
    59  			Err:     mangos.ErrNotRaw,
    60  		},
    61  	}, syscall.ENOENT))
    62  	MustBeTrue(t, isSyscallError(&net.OpError{
    63  		Op:     "test",
    64  		Net:    "none",
    65  		Source: nil,
    66  		Addr:   nil,
    67  		Err: &os.SyscallError{
    68  			Syscall: "none",
    69  			Err:     syscall.ENOENT,
    70  		},
    71  	}, syscall.ENOENT))
    72  }
    73  
    74  func TestIpcStaleListen(t *testing.T) {
    75  	addr1 := AddrTestIPC()
    76  	name := addr1[len("ipc://"):]
    77  	defer func() {
    78  		_ = os.Remove(name)
    79  		_ = os.Remove(name + ".hold")
    80  	}()
    81  
    82  	uaddr, _ := net.ResolveUnixAddr("unix", name)
    83  	sock, err := net.ListenUnix("unix", uaddr)
    84  
    85  	MustSucceed(t, err)
    86  
    87  	// We rename it so that closing won't unlink the socket.
    88  	// This lets us leave a stale socket behind.
    89  	MustSucceed(t, os.Rename(name, name+".hold"))
    90  	MustSucceed(t, sock.Close())
    91  	MustSucceed(t, os.Rename(name+".hold", name))
    92  
    93  	// Clean up the stale link.
    94  	self := GetMockSocket()
    95  
    96  	MustSucceed(t, self.Listen(addr1))
    97  	defer MustClose(t, self)
    98  }
    99  
   100  func TestIpcBusyListen(t *testing.T) {
   101  	addr1 := AddrTestIPC()
   102  	name := addr1[len("ipc://"):]
   103  
   104  	uaddr, _ := net.ResolveUnixAddr("unix", name)
   105  	sock, err := net.ListenUnix("unix", uaddr)
   106  	defer func() {
   107  		_ = sock.Close()
   108  	}()
   109  
   110  	MustSucceed(t, err)
   111  
   112  	self := GetMockSocket()
   113  
   114  	MustBeError(t, self.Listen(addr1), mangos.ErrAddrInUse)
   115  	defer MustClose(t, self)
   116  }
   117  
   118  func TestIpcFileConflictListen(t *testing.T) {
   119  	addr1 := AddrTestIPC()
   120  	name := addr1[len("ipc://"):]
   121  
   122  	file, err := os.Create(name)
   123  	MustSucceed(t, err)
   124  	_, _ = file.WriteString("abc")
   125  	_ = file.Close()
   126  	defer func() {
   127  		MustSucceed(t, os.Remove(name))
   128  	}()
   129  
   130  	self := GetMockSocket()
   131  
   132  	MustBeError(t, self.Listen(addr1), mangos.ErrAddrInUse)
   133  	defer MustClose(t, self)
   134  }
   135  
   136  type testAddr string
   137  
   138  func (a testAddr) testDial() (net.Conn, error) {
   139  	return net.Dial("unix", string(a)[len("ipc://"):])
   140  }
   141  
   142  func TestIpcAbortHandshake(t *testing.T) {
   143  	sock := GetMockSocket()
   144  	defer MustClose(t, sock)
   145  	addr := AddrTestIPC()
   146  	l, e := sock.NewListener(addr, nil)
   147  	MustSucceed(t, e)
   148  	MustSucceed(t, l.Listen())
   149  	c, e := testAddr(addr).testDial()
   150  	MustSucceed(t, e)
   151  	MustSucceed(t, c.Close())
   152  }
   153  
   154  func TestIpcBadHandshake(t *testing.T) {
   155  	sock := GetMockSocket()
   156  	defer MustClose(t, sock)
   157  	addr := AddrTestIPC()
   158  	l, e := sock.NewListener(addr, nil)
   159  	MustSucceed(t, e)
   160  	MustSucceed(t, l.Listen())
   161  	TranSendConnBadHandshakes(t, testAddr(addr).testDial)
   162  }
   163  
   164  func TestIpcBadRecv(t *testing.T) {
   165  	sock := GetMockSocket()
   166  	defer MustClose(t, sock)
   167  	addr := AddrTestIPC()
   168  	l, e := sock.NewListener(addr, nil)
   169  	MustSucceed(t, e)
   170  	MustSucceed(t, l.Listen())
   171  	TranSendBadMessages(t, sock.Info().Peer, true, testAddr(addr).testDial)
   172  }
   173  
   174  func TestIpcSendAbort(t *testing.T) {
   175  	sock := GetMockSocket()
   176  	defer MustClose(t, sock)
   177  	addr := AddrTestIPC()
   178  	l, e := sock.NewListener(addr, nil)
   179  	MustSucceed(t, e)
   180  	MustSucceed(t, l.Listen())
   181  	c, e := testAddr(addr).testDial()
   182  	MustSucceed(t, e)
   183  	TranConnHandshake(t, c, sock.Info().Peer)
   184  	MustSend(t, sock, make([]byte, 1024*1024))
   185  	time.Sleep(time.Millisecond * 100)
   186  	MustSucceed(t, c.Close())
   187  }
   188  
   189  func TestIpcListenerOptions(t *testing.T) {
   190  	sock := GetMockSocket()
   191  	defer MustClose(t, sock)
   192  	addr := AddrTestIPC()
   193  	l, e := tran.NewListener(addr, sock)
   194  	MustSucceed(t, e)
   195  
   196  	MustBeError(t, l.SetOption(OptionIpcSocketOwner, true), mangos.ErrBadValue)
   197  	MustBeError(t, l.SetOption(OptionIpcSocketGroup, true), mangos.ErrBadValue)
   198  	MustBeError(t, l.SetOption(OptionIpcSocketPermissions, true), mangos.ErrBadValue)
   199  	MustBeError(t, l.SetOption(OptionIpcSocketPermissions, os.ModeDir), mangos.ErrBadValue)
   200  	MustSucceed(t, l.SetOption(OptionIpcSocketPermissions, uint32(0642)))
   201  	MustSucceed(t, l.SetOption(OptionIpcSocketPermissions, os.FileMode(0642)))
   202  	MustSucceed(t, l.SetOption(OptionIpcSocketOwner, 0))
   203  	MustSucceed(t, l.SetOption(OptionIpcSocketGroup, 0))
   204  
   205  	MustSucceed(t, l.Listen())
   206  	i, e := os.Stat(strings.TrimPrefix(addr, "ipc://"))
   207  	MustSucceed(t, e)
   208  	MustBeTrue(t, i.Mode() & os.ModePerm == 0642)
   209  }