Skip to content

Commit

Permalink
unix socket support
Browse files Browse the repository at this point in the history
  • Loading branch information
nitely committed Aug 11, 2024
1 parent 2b874bb commit 2308a86
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 24 deletions.
2 changes: 1 addition & 1 deletion examples/dataStream.nim
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ when isMainModule:
await sendFut

proc main() {.async.} =
var client = newClient(localHost, localPort)
var client = newClient(localHost, localPort, ssl = false, domain = hyxUnix)
with client:
await streamChunks(client, "/foo")

Expand Down
6 changes: 3 additions & 3 deletions examples/localServer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import std/strutils
import std/asyncdispatch
import ../src/hyperx/server

const localHost* = "127.0.0.1"
const localPort* = Port 8783
const localHost* = "/tmp/hyperxasd22.sock"
const localPort* = Port 0
const certFile = getEnv "HYPERX_TEST_CERTFILE"
const keyFile = getEnv "HYPERX_TEST_KEYFILE"

Expand Down Expand Up @@ -76,7 +76,7 @@ proc serve*(server: ServerContext, propagateErr = true) {.async.} =

proc newServer*(): ServerContext =
newServer(
localHost, localPort, certFile, keyFile
localHost, localPort, certFile, keyFile, ssl = false, domain = hyxUnix
)

when isMainModule:
Expand Down
22 changes: 17 additions & 5 deletions src/hyperx/client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export
ClientContext,
HyperxConnError,
HyperxStrmError,
HyperxError
HyperxError,
HyperxSockDomain

var sslContext {.threadvar.}: SslContext

Expand All @@ -48,9 +49,13 @@ proc defaultSslContext(): SslContext {.raises: [HyperxConnError].} =
return sslContext

when not defined(hyperxTest):
proc newMySocket(ssl: bool): MyAsyncSocket {.raises: [HyperxConnError].} =
proc newMySocket(
domain: Domain, protocol: Protocol, ssl: bool
): MyAsyncSocket {.raises: [HyperxConnError].} =
doAssert domain in {AF_UNIX, AF_INET, AF_INET6}
doAssert protocol in {IPPROTO_IP, IPPROTO_TCP}
try:
result = newAsyncSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, buffered = true)
result = newAsyncSocket(domain, SOCK_STREAM, protocol, buffered = true)
if ssl:
wrapSocket(defaultSslContext(), result)
except CatchableError as err:
Expand All @@ -61,9 +66,16 @@ when not defined(hyperxTest):
proc newClient*(
hostname: string,
port = Port 443,
ssl = true
ssl = true,
domain = hyxInet
): ClientContext {.raises: [HyperxConnError].} =
newClient(ctClient, newMySocket(ssl), hostname, port)
newClient(
ctClient,
newMySocket(domain.addrFamily(), domain.ipProto(), ssl),
hostname,
port,
domain
)

type
HttpMethod* = enum
Expand Down
26 changes: 24 additions & 2 deletions src/hyperx/clientserver.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ const
stgServerMaxConcurrentStreams* {.intdefine: "hyperxMaxConcurrentStrms".} = 100
stgMaxSettingsList* {.intdefine: "hyperxMaxSettingsList".} = 100

type
HyperxSockDomain* = enum
hyxUnix, hyxInet, hyxInet6

func addrFamily*(domain: HyperxSockDomain): Domain {.raises: [].} =
case domain
of hyxUnix: AF_UNIX
of hyxInet: AF_INET
of hyxInet6: AF_INET6

func ipProto*(domain: HyperxSockDomain): Protocol {.raises: [].} =
case domain
of hyxUnix: IPPROTO_IP
of hyxInet, hyxInet6: IPPROTO_TCP

type
ClientTyp* = enum
ctServer, ctClient
Expand Down Expand Up @@ -123,6 +138,7 @@ type
sock*: MyAsyncSocket
hostname*: string
port: Port
domain: HyperxSockDomain
isConnected*: bool
headersEnc, headersDec: DynHeaders
streams: Streams
Expand All @@ -146,13 +162,15 @@ proc newClient*(
typ: ClientTyp,
sock: MyAsyncSocket,
hostname: string,
port = Port 443
port = Port 443,
domain = hyxInet
): ClientContext {.raises: [].} =
result = ClientContext(
typ: typ,
sock: sock,
hostname: hostname,
port: port,
domain: domain,
isConnected: false,
headersEnc: initDynHeaders(stgHeaderTableSize.int),
headersDec: initDynHeaders(stgHeaderTableSize.int),
Expand Down Expand Up @@ -756,7 +774,11 @@ proc windowUpdateTask(client: ClientContext) {.async.} =

proc connect(client: ClientContext) {.async.} =
try:
await client.sock.connect(client.hostname, client.port)
case client.domain
of hyxInet, hyxInet6:
await client.sock.connect(client.hostname, client.port)
of hyxUnix:
await client.sock.connectUnix(client.hostname)
except OsError as err:
debugInfo err.getStackTrace()
debugInfo err.msg
Expand Down
2 changes: 1 addition & 1 deletion src/hyperx/errors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func toErrorCode(e: uint32): ErrorCode {.raises: [].} =
# XXX remove ConnError and StrmError; expose code in Hyperx*
type
HyperxErrTyp* = enum
hxLocalErr, hxRemoteErr
hxLocalErr, hxRemoteErr # XXX use hyx prefix
HyperxError* = object of CatchableError
HyperxConnError* = object of HyperxError
HyperxStrmError* = object of HyperxError
Expand Down
45 changes: 35 additions & 10 deletions src/hyperx/server.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export
ClientContext,
HyperxConnError,
HyperxStrmError,
HyperxError
HyperxError,
#HyperxErrTyp,
HyperxSockDomain

var sslContext {.threadvar.}: SslContext

Expand All @@ -52,12 +54,16 @@ proc defaultSslContext(

when not defined(hyperxTest):
proc newMySocket(
domain: Domain,
protocol: Protocol,
ssl: bool,
certFile = "",
keyFile = ""
): MyAsyncSocket {.raises: [HyperxConnError].} =
doAssert domain in {AF_UNIX, AF_INET, AF_INET6}
doAssert protocol in {IPPROTO_IP, IPPROTO_TCP}
try:
result = newAsyncSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, buffered = true)
result = newAsyncSocket(domain, SOCK_STREAM, protocol, buffered = true)
if ssl:
wrapSocket(defaultSslContext(certFile, keyFile), result)
except CatchableError as err:
Expand All @@ -70,23 +76,28 @@ type
sock: MyAsyncSocket
hostname: string
port: Port
domain: HyperxSockDomain
isConnected: bool

proc newServer*(
hostname: string,
port: Port,
sslCertFile = "",
sslKeyFile = "",
ssl = true
ssl = true,
domain = hyxInet
): ServerContext =
ServerContext(
sock: newMySocket(
domain.addrFamily(),
domain.ipProto(),
ssl,
certFile = sslCertFile,
keyFile = sslKeyFile
),
hostname: hostname,
port: port,
domain: domain,
isConnected: false
)

Expand All @@ -107,12 +118,24 @@ proc close*(server: ServerContext) {.raises: [HyperxConnError].} =
debugInfo err.msg
raise newException(Defect, err.msg)

proc listen(server: ServerContext) =
server.sock.setSockOpt(OptReuseAddr, true)
server.sock.setSockOpt(OptReusePort, true)
server.sock.setSockOpt(OptNoDelay, true, level = IPPROTO_TCP.cint)
server.sock.bindAddr server.port
server.sock.listen()
proc listen(server: ServerContext) {.raises: [HyperxConnError].} =
try:
case server.domain
of hyxInet, hyxInet6:
server.sock.setSockOpt(OptReuseAddr, true)
server.sock.setSockOpt(OptReusePort, true)
server.sock.setSockOpt(OptNoDelay, true, level = IPPROTO_TCP.cint)
server.sock.bindAddr server.port
of hyxUnix:
# XXX tryRemoveFile to avoid OSError
server.sock.bindUnix server.hostname
server.sock.listen()
except OSError, ValueError:
let err = getCurrentException()
debugInfo err.getStackTrace()
debugInfo err.msg
# XXX probably not a conn error
raise newHyperxConnError(err.msg)

# XXX dont allow receive push promise

Expand All @@ -127,7 +150,9 @@ proc recvClient*(server: ServerContext): Future[ClientContext] {.async.} =
wrapConnectedSocket(
sslContext, sock, handshakeAsServer, server.hostname
)
result = newClient(ctServer, sock, server.hostname)
result = newClient(
ctServer, sock, server.hostname, server.port, server.domain
)
except CatchableError as err:
debugInfo err.getStackTrace()
debugInfo err.msg
Expand Down
10 changes: 8 additions & 2 deletions src/hyperx/testsocket.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ type
isConnected*: bool
hostname*: string
port*: Port
domain*: Domain
protocol*: Protocol
isSsl*: bool

proc newMySocket*(ssl: bool, certFile = "", keyFile = ""): TestSocket =
proc newMySocket*(
domain: Domain, protocol: Protocol, ssl: bool, certFile = "", keyFile = ""
): TestSocket =
TestSocket(
recvData: newQueue[seq[byte]](1000),
sentData: newQueue[seq[byte]](1000),
Expand All @@ -30,6 +34,8 @@ proc newMySocket*(ssl: bool, certFile = "", keyFile = ""): TestSocket =
isConnected: false,
hostname: "",
port: Port 0,
domain: domain,
protocol: protocol,
isSsl: ssl
)

Expand Down Expand Up @@ -110,7 +116,7 @@ proc listen*(s: TestSocket) =
s.isConnected = true

proc accept*(s: TestSocket): Future[TestSocket] {.async.} =
result = newMySocket(s.isSsl)
result = newMySocket(s.domain, s.isSsl)
result.isConnected = true

proc wrapConnectedSocket*(
Expand Down

0 comments on commit 2308a86

Please sign in to comment.