Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
capnproto
Commits
23b792a6
Commit
23b792a6
authored
Dec 04, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support DNS lookup.
parent
06fd35c4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
72 additions
and
56 deletions
+72
-56
ez-rpc-test.c++
c++/src/capnp/ez-rpc-test.c++
+2
-2
ez-rpc.c++
c++/src/capnp/ez-rpc.c++
+6
-6
async-io-test.c++
c++/src/kj/async-io-test.c++
+22
-18
async-io.c++
c++/src/kj/async-io.c++
+0
-0
async-io.h
c++/src/kj/async-io.h
+22
-24
thread.c++
c++/src/kj/thread.c++
+16
-6
thread.h
c++/src/kj/thread.h
+4
-0
No files found.
c++/src/capnp/ez-rpc-test.c++
View file @
23b792a6
...
...
@@ -30,12 +30,12 @@ namespace _ {
namespace
{
TEST
(
EzRpc
,
Basic
)
{
EzRpcServer
server
(
"
127.0.0.1
"
);
EzRpcServer
server
(
"
localhost
"
);
int
callCount
=
0
;
server
.
exportCap
(
"cap1"
,
kj
::
heap
<
TestInterfaceImpl
>
(
callCount
));
server
.
exportCap
(
"cap2"
,
kj
::
heap
<
TestCallOrderImpl
>
());
EzRpcClient
client
(
"
127.0.0.1
"
,
server
.
getPort
().
wait
());
EzRpcClient
client
(
"
localhost
"
,
server
.
getPort
().
wait
());
auto
cap
=
client
.
importCap
<
test
::
TestInterface
>
(
"cap1"
);
auto
request
=
cap
.
fooRequest
();
...
...
c++/src/capnp/ez-rpc.c++
View file @
23b792a6
...
...
@@ -102,8 +102,8 @@ struct EzRpcClient::Impl {
Impl
(
kj
::
StringPtr
serverAddress
,
uint
defaultPort
)
:
context
(
EzRpcContext
::
getThreadLocal
()),
setupPromise
(
context
->
getIoProvider
().
getNetwork
()
.
parse
Remote
Address
(
serverAddress
,
defaultPort
)
.
then
([](
kj
::
Own
<
kj
::
Remote
Address
>&&
addr
)
{
.
parseAddress
(
serverAddress
,
defaultPort
)
.
then
([](
kj
::
Own
<
kj
::
Network
Address
>&&
addr
)
{
return
addr
->
connect
();
}).
then
([
this
](
kj
::
Own
<
kj
::
AsyncIoStream
>&&
stream
)
{
clientContext
=
kj
::
heap
<
ClientContext
>
(
kj
::
mv
(
stream
));
...
...
@@ -112,7 +112,7 @@ struct EzRpcClient::Impl {
Impl
(
struct
sockaddr
*
serverAddress
,
uint
addrSize
)
:
context
(
EzRpcContext
::
getThreadLocal
()),
setupPromise
(
context
->
getIoProvider
().
getNetwork
()
.
get
Remote
Sockaddr
(
serverAddress
,
addrSize
)
->
connect
()
.
getSockaddr
(
serverAddress
,
addrSize
)
->
connect
()
.
then
([
this
](
kj
::
Own
<
kj
::
AsyncIoStream
>&&
stream
)
{
clientContext
=
kj
::
heap
<
ClientContext
>
(
kj
::
mv
(
stream
));
}).
fork
())
{}
...
...
@@ -196,10 +196,10 @@ struct EzRpcServer::Impl final: public SturdyRefRestorer<Text>, public kj::TaskS
auto
paf
=
kj
::
newPromiseAndFulfiller
<
uint
>
();
portPromise
=
paf
.
promise
.
fork
();
tasks
.
add
(
context
->
getIoProvider
().
getNetwork
().
parse
Local
Address
(
bindAddress
,
defaultPort
)
tasks
.
add
(
context
->
getIoProvider
().
getNetwork
().
parseAddress
(
bindAddress
,
defaultPort
)
.
then
(
kj
::
mvCapture
(
paf
.
fulfiller
,
[
this
](
kj
::
Own
<
kj
::
PromiseFulfiller
<
uint
>>&&
portFulfiller
,
kj
::
Own
<
kj
::
Local
Address
>&&
addr
)
{
kj
::
Own
<
kj
::
Network
Address
>&&
addr
)
{
auto
listener
=
addr
->
listen
();
portFulfiller
->
fulfill
(
listener
->
getPort
());
acceptLoop
(
kj
::
mv
(
listener
));
...
...
@@ -209,7 +209,7 @@ struct EzRpcServer::Impl final: public SturdyRefRestorer<Text>, public kj::TaskS
Impl
(
struct
sockaddr
*
bindAddress
,
uint
addrSize
)
:
context
(
EzRpcContext
::
getThreadLocal
()),
portPromise
(
nullptr
),
tasks
(
*
this
)
{
auto
listener
=
context
->
getIoProvider
().
getNetwork
()
.
get
Local
Sockaddr
(
bindAddress
,
addrSize
)
->
listen
();
.
getSockaddr
(
bindAddress
,
addrSize
)
->
listen
();
portPromise
=
kj
::
Promise
<
uint
>
(
listener
->
getPort
()).
fork
();
acceptLoop
(
kj
::
mv
(
listener
));
}
...
...
c++/src/kj/async-io-test.c++
View file @
23b792a6
...
...
@@ -42,8 +42,8 @@ TEST(AsyncIo, SimpleNetwork) {
auto
port
=
newPromiseAndFulfiller
<
uint
>
();
port
.
promise
.
then
([
&
](
uint
portnum
)
{
return
network
.
parse
RemoteAddress
(
"127.0.0.1
"
,
portnum
);
}).
then
([
&
](
Own
<
Remote
Address
>&&
result
)
{
return
network
.
parse
Address
(
"localhost
"
,
portnum
);
}).
then
([
&
](
Own
<
Network
Address
>&&
result
)
{
return
result
->
connect
();
}).
then
([
&
](
Own
<
AsyncIoStream
>&&
result
)
{
client
=
kj
::
mv
(
result
);
...
...
@@ -52,7 +52,7 @@ TEST(AsyncIo, SimpleNetwork) {
ADD_FAILURE
()
<<
kj
::
str
(
exception
).
cStr
();
});
kj
::
String
result
=
network
.
parse
LocalAddress
(
"*"
).
then
([
&
](
Own
<
Local
Address
>&&
result
)
{
kj
::
String
result
=
network
.
parse
Address
(
"*"
).
then
([
&
](
Own
<
Network
Address
>&&
result
)
{
listener
=
result
->
listen
();
port
.
fulfiller
->
fulfill
(
listener
->
getPort
());
return
listener
->
accept
();
...
...
@@ -67,28 +67,32 @@ TEST(AsyncIo, SimpleNetwork) {
EXPECT_EQ
(
"foo"
,
result
);
}
String
tryParseLocal
(
Network
&
network
,
StringPtr
text
,
uint
portHint
=
0
)
{
return
network
.
parseLocalAddress
(
text
,
portHint
).
wait
()
->
toString
();
}
String
tryParseRemote
(
Network
&
network
,
StringPtr
text
,
uint
portHint
=
0
)
{
return
network
.
parseRemoteAddress
(
text
,
portHint
).
wait
()
->
toString
();
String
tryParse
(
Network
&
network
,
StringPtr
text
,
uint
portHint
=
0
)
{
return
network
.
parseAddress
(
text
,
portHint
).
wait
()
->
toString
();
}
TEST
(
AsyncIo
,
AddressParsing
)
{
auto
ioContext
=
setupAsyncIo
();
auto
&
network
=
ioContext
.
provider
->
getNetwork
();
EXPECT_EQ
(
"*:0"
,
tryParseLocal
(
network
,
"*"
));
EXPECT_EQ
(
"*:123"
,
tryParseLocal
(
network
,
"123"
));
EXPECT_EQ
(
"*:123"
,
tryParseLocal
(
network
,
":123"
));
EXPECT_EQ
(
"[::]:123"
,
tryParseLocal
(
network
,
"0::0"
,
123
));
EXPECT_EQ
(
"0.0.0.0:0"
,
tryParseLocal
(
network
,
"0.0.0.0"
));
EXPECT_EQ
(
"1.2.3.4:5678"
,
tryParseRemote
(
network
,
"1.2.3.4"
,
5678
));
EXPECT_EQ
(
"[12ab:cd::34]:321"
,
tryParseRemote
(
network
,
"[12ab:cd:0::0:34]:321"
,
432
));
EXPECT_EQ
(
"*:0"
,
tryParse
(
network
,
"*"
));
EXPECT_EQ
(
"*:123"
,
tryParse
(
network
,
"*:123"
));
EXPECT_EQ
(
"[::]:123"
,
tryParse
(
network
,
"0::0"
,
123
));
EXPECT_EQ
(
"0.0.0.0:0"
,
tryParse
(
network
,
"0.0.0.0"
));
EXPECT_EQ
(
"1.2.3.4:5678"
,
tryParse
(
network
,
"1.2.3.4"
,
5678
));
EXPECT_EQ
(
"[12ab:cd::34]:321"
,
tryParse
(
network
,
"[12ab:cd:0::0:34]:321"
,
432
));
EXPECT_EQ
(
"unix:foo/bar/baz"
,
tryParse
(
network
,
"unix:foo/bar/baz"
));
// We can parse services by name...
EXPECT_EQ
(
"1.2.3.4:80"
,
tryParse
(
network
,
"1.2.3.4:http"
,
5678
));
EXPECT_EQ
(
"[::]:80"
,
tryParse
(
network
,
"[::]:http"
,
5678
));
EXPECT_EQ
(
"[12ab:cd::34]:80"
,
tryParse
(
network
,
"[12ab:cd::34]:http"
,
5678
));
EXPECT_EQ
(
"*:80"
,
tryParse
(
network
,
"*:http"
,
5678
));
EXPECT_EQ
(
"unix:foo/bar/baz"
,
tryParseLocal
(
network
,
"unix:foo/bar/baz"
));
EXPECT_EQ
(
"unix:foo/bar/baz"
,
tryParseRemote
(
network
,
"unix:foo/bar/baz"
));
// It would be nice to test DNS lookup here but the test would not be very hermetic. Even
// localhost can map to different addresses depending on whether IPv6 is enabled. We do
// connect to "localhost" in a different test, though.
}
TEST
(
AsyncIo
,
OneWayPipe
)
{
...
...
c++/src/kj/async-io.c++
View file @
23b792a6
This diff is collapsed.
Click to expand it.
c++/src/kj/async-io.h
View file @
23b792a6
...
...
@@ -68,12 +68,19 @@ public:
// specify a port when constructing the LocalAddress -- one will have been assigned automatically.
};
class
Remote
Address
{
class
Network
Address
{
// Represents a remote address to which the application can connect.
public
:
virtual
Promise
<
Own
<
AsyncIoStream
>>
connect
()
=
0
;
// Make a new connection to this address.
//
// The address must not be a wildcard ("*"). If it is an IP address, it must have a port number.
virtual
Own
<
ConnectionReceiver
>
listen
()
=
0
;
// Listen for incoming connections on this address.
//
// The address must be local.
virtual
String
toString
()
=
0
;
// Produce a human-readable string which hopefully can be passed to Network::parseRemoteAddress()
...
...
@@ -86,9 +93,6 @@ class LocalAddress {
// Represents a local address on which the application can potentially accept connections.
public
:
virtual
Own
<
ConnectionReceiver
>
listen
()
=
0
;
// Listen for incoming connections on this address.
virtual
String
toString
()
=
0
;
// Produce a human-readable string which hopefully can be passed to Network::parseRemoteAddress()
// to reproduce this address, although whether or not that works of course depends on the Network
...
...
@@ -105,30 +109,24 @@ class Network {
// LocalAddress and/or RemoteAddress instances directly and work from there, if at all possible.
public
:
virtual
Promise
<
Own
<
LocalAddress
>>
parseLocalAddress
(
StringPtr
addr
,
uint
portHint
=
0
)
=
0
;
virtual
Promise
<
Own
<
RemoteAddress
>>
parseRemoteAddress
(
StringPtr
addr
,
uint
portHint
=
0
)
=
0
;
// Construct a local or remote address from a user-provided string. The format of the address
virtual
Promise
<
Own
<
NetworkAddress
>>
parseAddress
(
StringPtr
addr
,
uint
portHint
=
0
)
=
0
;
// Construct a network address from a user-provided string. The format of the address
// strings is not specified at the API level, and application code should make no assumptions
// about them. These strings should always be provided by humans, and said humans will know
// what format to use in their particular context.
//
// `portHint`, if provided, specifies the "standard" IP port number for the application-level
// service in play. If the address turns out to be an IP address (v4 or v6), and it lacks a
// port number, this port will be used.
//
// In practice, a local address is usually just a port number (or even an empty string, if a
// reasonable `portHint` is provided), whereas a remote address usually requires a hostname.
// port number, this port will be used. If `addr` lacks a port number *and* `portHint` is
// omitted, then the returned address will only support listen() (not connect()), and a port
// will be chosen when listen() is called.
virtual
Own
<
LocalAddress
>
getLocalSockaddr
(
const
void
*
sockaddr
,
uint
len
)
=
0
;
virtual
Own
<
RemoteAddress
>
getRemoteSockaddr
(
const
void
*
sockaddr
,
uint
len
)
=
0
;
// Construct a local or remote address from a legacy struct sockaddr.
virtual
Own
<
NetworkAddress
>
getSockaddr
(
const
void
*
sockaddr
,
uint
len
)
=
0
;
// Construct a network address from a legacy struct sockaddr.
};
struct
OneWayPipe
{
// A data pipe with an input end and an output end. The two ends are safe to use in different
// threads. (Typically backed by pipe() system call.)
// A data pipe with an input end and an output end. (Typically backed by pipe() system call.)
Own
<
AsyncInputStream
>
in
;
Own
<
AsyncOutputStream
>
out
;
...
...
@@ -136,8 +134,7 @@ struct OneWayPipe {
struct
TwoWayPipe
{
// A data pipe that supports sending in both directions. Each end's output sends data to the
// other end's input. The ends can be used in separate threads. (Typically backed by
// socketpair() system call.)
// other end's input. (Typically backed by socketpair() system call.)
Own
<
AsyncIoStream
>
ends
[
2
];
};
...
...
@@ -175,7 +172,8 @@ public:
// With that said, KJ currently supports the following string address formats:
// - IPv4: "1.2.3.4", "1.2.3.4:80"
// - IPv6: "1234:5678::abcd", "[1234:5678::abcd]:80"
// - Local IP wildcard (local addresses only; covers both v4 and v6): "*", "*:80", ":80", "80"
// - Local IP wildcard (covers both v4 and v6): "*", "*:80"
// - Symbolic names: "example.com", "example.com:80", "example.com:http", "1.2.3.4:http"
// - Unix domain: "unix:/path/to/socket"
struct
PipeThread
{
...
...
@@ -284,7 +282,7 @@ struct AsyncIoContext {
AsyncIoContext
setupAsyncIo
();
// Convenience method which sets up the current thread with everything it needs to do async I/O.
// The returned object
contains
an `EventLoop` which is wrapping an appropriate `EventPort` for
// The returned object
s contain
an `EventLoop` which is wrapping an appropriate `EventPort` for
// doing I/O on the host system, so everything is ready for the thread to start making async calls
// and waiting on promises.
//
...
...
@@ -292,10 +290,10 @@ AsyncIoContext setupAsyncIo();
// Example:
//
// int main() {
// auto io
System = kj::setupIoEventLoop
();
// auto io
Context = kj::setupAsyncIo
();
//
// // Now we can call an async function.
// Promise<String> textPromise = getHttp(
ioSystem->getNetwork()
, "http://example.com");
// Promise<String> textPromise = getHttp(
*ioContext.provider
, "http://example.com");
//
// // And we can wait for the promise to complete. Note that you can only use `wait()`
// // from the top level, not from inside a promise callback.
...
...
c++/src/kj/thread.c++
View file @
23b792a6
...
...
@@ -40,13 +40,15 @@ Thread::Thread(Function<void()> func): func(kj::mv(func)) {
}
Thread
::~
Thread
()
noexcept
(
false
)
{
int
pthreadResult
=
pthread_join
(
*
reinterpret_cast
<
pthread_t
*>
(
&
threadId
),
nullptr
);
if
(
pthreadResult
!=
0
)
{
KJ_FAIL_SYSCALL
(
"pthread_join"
,
pthreadResult
)
{
break
;
}
}
if
(
!
detached
)
{
int
pthreadResult
=
pthread_join
(
*
reinterpret_cast
<
pthread_t
*>
(
&
threadId
),
nullptr
);
if
(
pthreadResult
!=
0
)
{
KJ_FAIL_SYSCALL
(
"pthread_join"
,
pthreadResult
)
{
break
;
}
}
KJ_IF_MAYBE
(
e
,
exception
)
{
kj
::
throwRecoverableException
(
kj
::
mv
(
*
e
));
KJ_IF_MAYBE
(
e
,
exception
)
{
kj
::
throwRecoverableException
(
kj
::
mv
(
*
e
));
}
}
}
...
...
@@ -57,6 +59,14 @@ void Thread::sendSignal(int signo) {
}
}
void
Thread
::
detach
()
{
int
pthreadResult
=
pthread_detach
(
*
reinterpret_cast
<
pthread_t
*>
(
&
threadId
));
if
(
pthreadResult
!=
0
)
{
KJ_FAIL_SYSCALL
(
"pthread_detach"
,
pthreadResult
)
{
break
;
}
}
detached
=
true
;
}
void
*
Thread
::
runThread
(
void
*
ptr
)
{
Thread
*
thread
=
reinterpret_cast
<
Thread
*>
(
ptr
);
KJ_IF_MAYBE
(
exception
,
kj
::
runCatchingExceptions
([
&
]()
{
...
...
c++/src/kj/thread.h
View file @
23b792a6
...
...
@@ -43,10 +43,14 @@ public:
void
sendSignal
(
int
signo
);
// Send a Unix signal to the given thread, using pthread_kill or an equivalent.
void
detach
();
// Don't join the thread in ~Thread().
private
:
Function
<
void
()
>
func
;
unsigned
long
long
threadId
;
// actually pthread_t
kj
::
Maybe
<
kj
::
Exception
>
exception
;
bool
detached
=
false
;
static
void
*
runThread
(
void
*
ptr
);
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment