-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathio.nim
More file actions
153 lines (134 loc) · 4.15 KB
/
Copy pathio.nim
File metadata and controls
153 lines (134 loc) · 4.15 KB
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
143
144
145
146
147
148
149
150
151
152
153
# SPDX-License-Identifier: Apache-2.0 OR MIT
# Copyright (c) Status Research & Development GmbH
import chronos
import chronos/osdefs
import chronicles
import ./context
import ../[lsquic_ffi, datagram]
import ../helpers/[openarray, sequninit, transportaddr]
import std/[nativesockets, net]
when not defined(windows):
import posix
when defined(windows):
import std/winlean
{.pragma: wsa, stdcall, dynlib: "ws2_32.dll".}
type WSABUF* = object
len*: culong
buf*: ptr char
proc WSASendTo*(
s: SocketHandle,
lpBuffers: ptr WSABUF,
dwBufferCount: culong,
lpNumberOfBytesSent: ptr culong,
dwFlags: culong,
lpTo: ptr SockAddr,
iToLen: cint,
lpOverlapped: pointer,
lpCompletionRoutine: pointer,
): cint {.wsa, importc: "WSASendTo".}
proc prepareDestAddr(
localSa: ptr SockAddr,
destSa: ptr SockAddr,
destStorage: var Sockaddr_storage,
destAddrLen: var SockLen,
) =
## Chronos normalizes IPv4 peers on dual-stack `::` sockets back to IPv4.
## When lsquic later asks us to send on that IPv6 socket, sending directly to
## an AF_INET destination can fail with EINVAL. Re-map the destination to an
## IPv6-mapped address when the local path is IPv6.
let
localAddress = localSa.toTransportAddress()
destAddress = destSa.toTransportAddress()
if localAddress.family == AddressFamily.IPv6 and
destAddress.family == AddressFamily.IPv4:
let mappedDest = destAddress.toIPv6()
mappedDest.toSAddr(destStorage, destAddrLen)
else:
destAddrLen = sockAddrLen(destSa.sa_family.int)
copyMem(addr destStorage, destSa, destAddrLen)
proc receive*(
ctx: QuicContext,
datagram: sink Datagram,
local: TransportAddress,
remote: TransportAddress,
) =
if datagram.len == 0 or not ctx.isRunning():
return
var
localAddress: Sockaddr_storage
localAddrLen: SockLen
remoteAddress: Sockaddr_storage
remoteAddrLen: SockLen
local.toSAddr(localAddress, localAddrLen)
remote.toSAddr(remoteAddress, remoteAddrLen)
discard lsquic_engine_packet_in(
ctx.engine,
datagram.data.toPtr,
datagram.data.len.csize_t,
cast[ptr SockAddr](addr localAddress),
cast[ptr SockAddr](addr remoteAddress),
cast[pointer](ctx),
datagram.ecn,
)
ctx.processWhenReady()
proc sendPacketsOut*(
ctx: pointer, specs: ptr struct_lsquic_out_spec, nspecs: cuint
): cint {.cdecl.} =
let quicCtx = cast[QuicContext](ctx)
var sent = 0
let specsArr = cast[ptr UncheckedArray[struct_lsquic_out_spec]](specs)
for i in 0 ..< nspecs.int:
let curr = specsArr[i]
var
destStorage: Sockaddr_storage
destAddrLen: SockLen
prepareDestAddr(curr.local_sa, curr.dest_sa, destStorage, destAddrLen)
when defined(windows):
let iovArr = cast[ptr UncheckedArray[struct_iovec]](curr.iov)
var bufs = newSeq[WSABUF](curr.iovlen.int)
for j in 0 ..< curr.iovlen.int:
let src = iovArr[j]
bufs[j].len = culong(src.iov_len)
bufs[j].buf = cast[ptr char](src.iov_base)
var bytesSent: culong = 0
let res = WSASendTo(
SocketHandle(quicCtx.fd),
addr bufs[0],
culong(curr.iovlen),
addr bytesSent,
0, # flags
cast[ptr SockAddr](addr destStorage),
cint(destAddrLen),
nil,
nil, # no overlapped
)
if res != 0:
break
else:
let msg =
when defined(linux) and defined(x86_64):
Tmsghdr(
msg_name: cast[pointer](addr destStorage),
msg_namelen: destAddrLen,
msg_iov: cast[ptr IOVec](curr.iov),
msg_iovlen: curr.iovlen.csize_t,
msg_control: nil,
msg_controllen: 0,
msg_flags: 0,
)
else:
Tmsghdr(
msg_name: cast[pointer](addr destStorage),
msg_namelen: destAddrLen,
msg_iov: cast[ptr IOVec](curr.iov),
msg_iovlen: curr.iovlen.cint,
msg_control: nil,
msg_controllen: 0,
msg_flags: 0,
)
let res = sendmsg(SocketHandle(quicCtx.fd), msg.addr, 0)
if res < 0:
trace "sendmsg failed", sent, nspecs
break
sent.inc
sent.cint