about summary refs log tree commit diff stats
path: root/archive/0.vm.arc/x.mu
Commit message (Expand)AuthorAgeFilesLines
* 5852Kartik Agaram2020-01-011-0/+6
' href='/ahoang/chawan/blame/src/io/socketstream.nim?id=3223a3364ae9f17dd2dc25bcbf2e644380db462f'>^
896489a6 ^
e38402df ^
0cfe4091 ^
51ea622d ^


1e858c87 ^
04fe0c11 ^
e38402df ^

0cfe4091 ^
940325ab ^
e38402df ^


4b482418 ^
e38402df ^
21178cc6 ^
940325ab ^

08722702 ^
08722702 ^
4b482418 ^




08722702 ^
4b482418 ^
940325ab ^

4b482418 ^
21178cc6 ^

4b482418 ^
e38402df ^
7b6a2c6d ^
eb2e57c9 ^
e38402df ^


940325ab ^

08722702 ^



e38402df ^





51ea622d ^
e38402df ^
b086e346 ^



1c61efbc ^




b086e346 ^






339a167f ^
1c61efbc ^



7b6a2c6d ^


339a167f ^


b086e346 ^









b086e346 ^
7b6a2c6d ^
b086e346 ^





7b6a2c6d ^


b086e346 ^






51ea622d ^
e38402df ^
0cfe4091 ^


e38402df ^


51ea622d ^
4df668fd ^
51ea622d ^
940325ab ^
896489a6 ^
15e6a231 ^

51ea622d ^


4df668fd ^
896489a6 ^
4df668fd ^
896489a6 ^

51ea622d ^
940325ab ^
51ea622d ^
940325ab ^
51ea622d ^
896489a6 ^
51ea622d ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
                    
          
         
              
 


                    
                     
                       

                                         
                 
            


                                                              
                 
                         
                      

                       
                                                                                    
               




                       
             
                 

                                       
                 

                                         
                  
                
                       
                   


                                                          

                



                                                                                      





                                                        
                  
 



                                                       




                                           






                                
           



                                                      


                                                                  


                                                









                                                   
               
                                                              





                                


                                                       






                                                                               
                                       
             


                                                                                   


                                      
 
                                                                                         
                            
                       
                                                                                           

                                   


                         
                                                                                     
      
                                                               

                 
 
                                                                              
                            
                       
                  
                                             
                      
import nativesockets
import net
import os
import streams

when defined(posix):
  import posix

import io/posixstream
import ips/serversocket

type SocketStream* = ref object of Stream
  source*: Socket
  blk*: bool
  isend: bool

proc sockReadData(s: Stream, buffer: pointer, len: int): int =
  assert len != 0
  let s = SocketStream(s)
  let wasend = s.isend
  if s.blk:
    while result < len:
      let n = s.source.recv(cast[pointer](cast[int](buffer) + result), len - result)
      if n < 0:
        if result == 0:
          result = n
        break
      elif n == 0:
        s.isend = true
        break
      result += n
  else:
    result = s.source.recv(buffer, len)
  if result == 0:
    if wasend:
      raise newException(EOFError, "eof")
    s.isend = true
  if result < 0:
    raisePosixIOError()
  elif result == 0:
    s.isend = true

proc sockWriteData(s: Stream, buffer: pointer, len: int) =
  var i = 0
  while i < len:
    let n = SocketStream(s).source.send(cast[pointer](cast[int](buffer) + i), len - i)
    if n < 0:
      raise newException(IOError, $strerror(errno))
    i += n

proc sockAtEnd(s: Stream): bool =
  SocketStream(s).isend

proc sockClose(s: Stream) = {.cast(tags: []).}: #...sigh
  let s = SocketStream(s)
  s.source.close()

# See https://stackoverflow.com/a/4491203
proc sendFileHandle*(s: SocketStream, fd: FileHandle) =
  var hdr: Tmsghdr
  var iov: IOVec
  var space: csize_t
  {.emit: [
  space, """ = CMSG_SPACE(sizeof(int));""",
  ].}
  var cmsgbuf = alloc(cast[int](space))
  var buf = char(0)
  iov.iov_base = addr buf
  iov.iov_len = csize_t(1)
  zeroMem(addr hdr, sizeof(hdr))
  hdr.msg_iov = addr iov
  hdr.msg_iovlen = 1
  hdr.msg_control = cmsgbuf
  # ...sigh
  {.emit: [
  hdr.msg_controllen, """ = CMSG_LEN(sizeof(int));""",
  ].}
  let cmsg = CMSG_FIRSTHDR(addr hdr)
  # FileHandle is cint, so sizeof(FileHandle) in c is sizeof(int).
  when sizeof(FileHandle) != sizeof(cint):
    error("Or not...")
  {.emit: [
  cmsg.cmsg_len, """ = CMSG_LEN(sizeof(int));"""
  ].}
  cmsg.cmsg_level = SOL_SOCKET
  cmsg.cmsg_type = SCM_RIGHTS
  cast[ptr FileHandle](CMSG_DATA(cmsg))[] = fd
  let n = sendmsg(s.source.getFd(), addr hdr, 0)
  dealloc(cmsgbuf)
  assert n == int(iov.iov_len) #TODO remove this

proc recvFileHandle*(s: SocketStream): FileHandle =
  var iov: IOVec
  var hdr: Tmsghdr
  var buf: char
  var cmsgbuf = alloc(CMSG_SPACE(csize_t(sizeof(FileHandle))))
  iov.iov_base = addr buf
  iov.iov_len = 1
  zeroMem(addr hdr, sizeof(hdr))
  hdr.msg_iov = addr iov
  hdr.msg_iovlen = 1
  hdr.msg_control = cmsgbuf
  {.emit: [
  hdr.msg_controllen, """ = CMSG_SPACE(sizeof(int));"""
  ].}
  let n = recvmsg(s.source.getFd(), addr hdr, 0)
  assert n != 0, "Unexpected EOF" #TODO remove this
  assert n > 0, "Failed to receive message " & $osLastError() #TODO remove this
  var cmsg = CMSG_FIRSTHDR(addr hdr)
  result = cast[ptr FileHandle](CMSG_DATA(cmsg))[]
  dealloc(cmsgbuf)

func newSocketStream*(): SocketStream =
  new(result)
  result.readDataImpl = cast[proc (s: Stream, buffer: pointer, bufLen: int): int
      {.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.}
  ](sockReadData) # ... ???
  result.writeDataImpl = sockWriteData
  result.atEndImpl = sockAtEnd
  result.closeImpl = sockClose

proc connectSocketStream*(path: string, buffered = true, blocking = true): SocketStream =
  result = newSocketStream()
  result.blk = blocking
  let sock = newSocket(Domain.AF_UNIX, SockType.SOCK_STREAM, Protocol.IPPROTO_IP, buffered)
  if not blocking:
    sock.getFd().setBlocking(false)
  connectUnix(sock, path)
  result.source = sock

proc connectSocketStream*(pid: Pid, buffered = true, blocking = true): SocketStream =
  try:
    connectSocketStream(getSocketPath(pid), buffered, blocking)
  except OSError:
    return nil

proc acceptSocketStream*(ssock: ServerSocket, blocking = true): SocketStream =
  result = newSocketStream()
  result.blk = blocking
  var sock: Socket
  ssock.sock.accept(sock, inheritable = true)
  result.source = sock