Implement UDP socket support.
This commit is contained in:
parent
2a8c52f347
commit
c4e985b73c
|
@ -25,7 +25,7 @@ Driver development status
|
||||||
Feature | SelectEventDriver | EpollEventDriver | IOCPEventDriver | KqueueEventDriver
|
Feature | SelectEventDriver | EpollEventDriver | IOCPEventDriver | KqueueEventDriver
|
||||||
-----------------|-------------------|------------------|-----------------|------------------
|
-----------------|-------------------|------------------|-----------------|------------------
|
||||||
TCP Sockets | yes | yes | no | no
|
TCP Sockets | yes | yes | no | no
|
||||||
UDP Sockets | no | no | no | no
|
UDP Sockets | yes | yes | no | no
|
||||||
USDS | no | no | no | no
|
USDS | no | no | no | no
|
||||||
DNS | no | no | no | no
|
DNS | no | no | no | no
|
||||||
Timers | yes | yes | no | no
|
Timers | yes | yes | no | no
|
||||||
|
|
|
@ -83,11 +83,17 @@ interface EventDriverSockets {
|
||||||
ConnectionState getConnectionState(StreamSocketFD sock);
|
ConnectionState getConnectionState(StreamSocketFD sock);
|
||||||
void setTCPNoDelay(StreamSocketFD socket, bool enable);
|
void setTCPNoDelay(StreamSocketFD socket, bool enable);
|
||||||
void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish);
|
void read(StreamSocketFD socket, ubyte[] buffer, IOMode mode, IOCallback on_read_finish);
|
||||||
|
void cancelRead(StreamSocketFD socket);
|
||||||
void write(StreamSocketFD socket, const(ubyte)[] buffer, IOMode mode, IOCallback on_write_finish);
|
void write(StreamSocketFD socket, const(ubyte)[] buffer, IOMode mode, IOCallback on_write_finish);
|
||||||
|
void cancelWrite(StreamSocketFD socket);
|
||||||
void waitForData(StreamSocketFD socket, IOCallback on_data_available);
|
void waitForData(StreamSocketFD socket, IOCallback on_data_available);
|
||||||
void shutdown(StreamSocketFD socket, bool shut_read = true, bool shut_write = true);
|
void shutdown(StreamSocketFD socket, bool shut_read = true, bool shut_write = true);
|
||||||
void cancelRead(StreamSocketFD socket);
|
|
||||||
void cancelWrite(StreamSocketFD socket);
|
DatagramSocketFD createDatagramSocket(scope Address bind_address, scope Address target_address);
|
||||||
|
void receive(DatagramSocketFD socket, ubyte[] buffer, IOMode mode, DatagramIOCallback on_receive_finish);
|
||||||
|
void cancelReceive(DatagramSocketFD socket);
|
||||||
|
void send(DatagramSocketFD socket, const(ubyte)[] buffer, IOMode mode, DatagramIOCallback on_send_finish, Address target_address = null);
|
||||||
|
void cancelSend(DatagramSocketFD socket);
|
||||||
|
|
||||||
/** Increments the reference count of the given resource.
|
/** Increments the reference count of the given resource.
|
||||||
*/
|
*/
|
||||||
|
@ -195,6 +201,7 @@ interface EventDriverWatchers {
|
||||||
alias ConnectCallback = void delegate(StreamSocketFD, ConnectStatus);
|
alias ConnectCallback = void delegate(StreamSocketFD, ConnectStatus);
|
||||||
alias AcceptCallback = void delegate(StreamListenSocketFD, StreamSocketFD);
|
alias AcceptCallback = void delegate(StreamListenSocketFD, StreamSocketFD);
|
||||||
alias IOCallback = void delegate(StreamSocketFD, IOStatus, size_t);
|
alias IOCallback = void delegate(StreamSocketFD, IOStatus, size_t);
|
||||||
|
alias DatagramIOCallback = void delegate(DatagramSocketFD, IOStatus, size_t, scope Address);
|
||||||
alias FileIOCallback = void delegate(FileFD, IOStatus, size_t);
|
alias FileIOCallback = void delegate(FileFD, IOStatus, size_t);
|
||||||
alias EventCallback = void delegate(EventID);
|
alias EventCallback = void delegate(EventID);
|
||||||
alias SignalCallback = void delegate(int);
|
alias SignalCallback = void delegate(int);
|
||||||
|
@ -302,6 +309,7 @@ alias FD = Handle!("FD", int, -1);
|
||||||
alias SocketFD = Handle!("Socket", FD);
|
alias SocketFD = Handle!("Socket", FD);
|
||||||
alias StreamSocketFD = Handle!("Stream", SocketFD);
|
alias StreamSocketFD = Handle!("Stream", SocketFD);
|
||||||
alias StreamListenSocketFD = Handle!("StreamListen", SocketFD);
|
alias StreamListenSocketFD = Handle!("StreamListen", SocketFD);
|
||||||
|
alias DatagramSocketFD = Handle!("Datagram", SocketFD);
|
||||||
alias FileFD = Handle!("File", FD);
|
alias FileFD = Handle!("File", FD);
|
||||||
alias EventID = Handle!("Event", FD);
|
alias EventID = Handle!("Event", FD);
|
||||||
alias TimerID = Handle!("Timer", int);
|
alias TimerID = Handle!("Timer", int);
|
||||||
|
|
|
@ -135,7 +135,7 @@ abstract class PosixEventDriver : EventDriver,
|
||||||
|
|
||||||
final override StreamSocketFD connectStream(scope Address address, ConnectCallback on_connect)
|
final override StreamSocketFD connectStream(scope Address address, ConnectCallback on_connect)
|
||||||
{
|
{
|
||||||
auto sock = cast(StreamSocketFD)createSocket(address.addressFamily);
|
auto sock = cast(StreamSocketFD)createSocket(address.addressFamily, SOCK_STREAM);
|
||||||
if (sock == -1) return StreamSocketFD.invalid;
|
if (sock == -1) return StreamSocketFD.invalid;
|
||||||
|
|
||||||
void invalidateSocket() @nogc @trusted nothrow { closeSocket(sock); sock = StreamSocketFD.invalid; }
|
void invalidateSocket() @nogc @trusted nothrow { closeSocket(sock); sock = StreamSocketFD.invalid; }
|
||||||
|
@ -187,7 +187,7 @@ abstract class PosixEventDriver : EventDriver,
|
||||||
final override StreamListenSocketFD listenStream(scope Address address, AcceptCallback on_accept)
|
final override StreamListenSocketFD listenStream(scope Address address, AcceptCallback on_accept)
|
||||||
{
|
{
|
||||||
log("Listen stream");
|
log("Listen stream");
|
||||||
auto sock = cast(StreamListenSocketFD)createSocket(address.addressFamily);
|
auto sock = cast(StreamListenSocketFD)createSocket(address.addressFamily, SOCK_STREAM);
|
||||||
|
|
||||||
void invalidateSocket() @nogc @trusted nothrow { closeSocket(sock); sock = StreamSocketFD.invalid; }
|
void invalidateSocket() @nogc @trusted nothrow { closeSocket(sock); sock = StreamSocketFD.invalid; }
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ abstract class PosixEventDriver : EventDriver,
|
||||||
}
|
}
|
||||||
|
|
||||||
sizediff_t ret;
|
sizediff_t ret;
|
||||||
() @trusted { ret = recv(socket, buffer.ptr, buffer.length, 0); } ();
|
() @trusted { ret = .recv(socket, buffer.ptr, buffer.length, 0); } ();
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
auto err = getSocketError();
|
auto err = getSocketError();
|
||||||
|
@ -323,7 +323,7 @@ abstract class PosixEventDriver : EventDriver,
|
||||||
}
|
}
|
||||||
|
|
||||||
sizediff_t ret;
|
sizediff_t ret;
|
||||||
() @trusted { ret = recv(socket, slot.readBuffer.ptr, slot.readBuffer.length, 0); } ();
|
() @trusted { ret = .recv(socket, slot.readBuffer.ptr, slot.readBuffer.length, 0); } ();
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
auto err = getSocketError();
|
auto err = getSocketError();
|
||||||
if (err != EAGAIN) {
|
if (err != EAGAIN) {
|
||||||
|
@ -355,7 +355,7 @@ abstract class PosixEventDriver : EventDriver,
|
||||||
}
|
}
|
||||||
|
|
||||||
sizediff_t ret;
|
sizediff_t ret;
|
||||||
() @trusted { ret = send(socket, buffer.ptr, buffer.length, 0); } ();
|
() @trusted { ret = .send(socket, buffer.ptr, buffer.length, 0); } ();
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
auto err = getSocketError();
|
auto err = getSocketError();
|
||||||
|
@ -398,11 +398,9 @@ abstract class PosixEventDriver : EventDriver,
|
||||||
|
|
||||||
override void cancelWrite(StreamSocketFD socket)
|
override void cancelWrite(StreamSocketFD socket)
|
||||||
{
|
{
|
||||||
assert(m_fds[socket].readCallback !is null, "Cancelling write when there is no read in progress.");
|
assert(m_fds[socket].writeCallback !is null, "Cancelling write when there is no write in progress.");
|
||||||
setNotifyCallback!(EventType.write)(socket, null);
|
setNotifyCallback!(EventType.write)(socket, null);
|
||||||
with (m_fds[socket]) {
|
m_fds[socket].writeBuffer = null;
|
||||||
writeBuffer = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSocketWrite(FD fd)
|
private void onSocketWrite(FD fd)
|
||||||
|
@ -411,13 +409,13 @@ abstract class PosixEventDriver : EventDriver,
|
||||||
auto socket = cast(StreamSocketFD)fd;
|
auto socket = cast(StreamSocketFD)fd;
|
||||||
|
|
||||||
sizediff_t ret;
|
sizediff_t ret;
|
||||||
() @trusted { ret = send(socket, slot.writeBuffer.ptr, slot.writeBuffer.length, 0); } ();
|
() @trusted { ret = .send(socket, slot.writeBuffer.ptr, slot.writeBuffer.length, 0); } ();
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
auto err = getSocketError();
|
auto err = getSocketError();
|
||||||
if (err != EAGAIN) {
|
if (err != EAGAIN) {
|
||||||
setNotifyCallback!(EventType.write)(socket, null);
|
setNotifyCallback!(EventType.write)(socket, null);
|
||||||
slot.readCallback(socket, IOStatus.error, slot.bytesRead);
|
slot.writeCallback(socket, IOStatus.error, slot.bytesRead);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,6 +499,167 @@ abstract class PosixEventDriver : EventDriver,
|
||||||
// TODO!
|
// TODO!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DatagramSocketFD createDatagramSocket(scope Address bind_address, scope Address target_address)
|
||||||
|
{
|
||||||
|
auto sock = cast(DatagramSocketFD)createSocket(bind_address.addressFamily, SOCK_DGRAM);
|
||||||
|
if (sock == -1) return DatagramSocketFD.invalid;
|
||||||
|
|
||||||
|
if (() @trusted { return bind(sock, bind_address.name, bind_address.nameLen); } () != 0) {
|
||||||
|
closeSocket(sock);
|
||||||
|
return DatagramSocketFD.init;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_address && () @trusted { return connect(sock, target_address.name, target_address.nameLen); } () != 0) {
|
||||||
|
closeSocket(sock);
|
||||||
|
return DatagramSocketFD.init;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerFD(sock, EventMask.read|EventMask.write|EventMask.status);
|
||||||
|
|
||||||
|
initFD(sock);
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void receive(DatagramSocketFD socket, ubyte[] buffer, IOMode mode, DatagramIOCallback on_receive_finish)
|
||||||
|
{
|
||||||
|
assert(mode != IOMode.all, "Only IOMode.immediate and IOMode.once allowed for datagram sockets.");
|
||||||
|
|
||||||
|
sizediff_t ret;
|
||||||
|
scope src_addr = new UnknownAddress;
|
||||||
|
socklen_t src_addr_len = src_addr.nameLen;
|
||||||
|
() @trusted { ret = .recvfrom(socket, buffer.ptr, buffer.length, 0, src_addr.name, &src_addr_len); } ();
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
auto err = getSocketError();
|
||||||
|
if (err != EAGAIN) {
|
||||||
|
print("sock error %s!", err);
|
||||||
|
on_receive_finish(socket, IOStatus.error, 0, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
if (mode == IOMode.immediate) {
|
||||||
|
on_receive_finish(socket, IOStatus.wouldBlock, 0, null);
|
||||||
|
} else {
|
||||||
|
with (m_fds[socket]) {
|
||||||
|
readCallback = () @trusted { return cast(IOCallback)on_receive_finish; } ();
|
||||||
|
readMode = mode;
|
||||||
|
bytesRead = 0;
|
||||||
|
readBuffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNotifyCallback!(EventType.read)(socket, &onDgramRead);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
on_receive_finish(socket, IOStatus.ok, ret, src_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancelReceive(DatagramSocketFD socket)
|
||||||
|
{
|
||||||
|
assert(m_fds[socket].readCallback !is null, "Cancelling read when there is no read in progress.");
|
||||||
|
setNotifyCallback!(EventType.read)(socket, null);
|
||||||
|
m_fds[socket].readBuffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDgramRead(FD fd)
|
||||||
|
{
|
||||||
|
auto slot = &m_fds[fd];
|
||||||
|
auto socket = cast(DatagramSocketFD)fd;
|
||||||
|
|
||||||
|
sizediff_t ret;
|
||||||
|
scope src_addr = new UnknownAddress;
|
||||||
|
socklen_t src_addr_len = src_addr.nameLen;
|
||||||
|
() @trusted { ret = .recvfrom(socket, slot.readBuffer.ptr, slot.readBuffer.length, 0, src_addr.name, &src_addr_len); } ();
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
auto err = getSocketError();
|
||||||
|
if (err != EAGAIN) {
|
||||||
|
setNotifyCallback!(EventType.read)(socket, null);
|
||||||
|
() @trusted { return cast(DatagramIOCallback)slot.readCallback; } ()(socket, IOStatus.error, 0, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setNotifyCallback!(EventType.read)(socket, null);
|
||||||
|
() @trusted { return cast(DatagramIOCallback)slot.readCallback; } ()(socket, IOStatus.ok, ret, src_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(DatagramSocketFD socket, const(ubyte)[] buffer, IOMode mode, DatagramIOCallback on_send_finish, Address target_address = null)
|
||||||
|
{
|
||||||
|
assert(mode != IOMode.all, "Only IOMode.immediate and IOMode.once allowed for datagram sockets.");
|
||||||
|
|
||||||
|
sizediff_t ret;
|
||||||
|
if (target_address) {
|
||||||
|
() @trusted { ret = .sendto(socket, buffer.ptr, buffer.length, 0, target_address.name, target_address.nameLen); } ();
|
||||||
|
m_fds[socket].targetAddr = target_address;
|
||||||
|
} else {
|
||||||
|
() @trusted { ret = .send(socket, buffer.ptr, buffer.length, 0); } ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
auto err = getSocketError();
|
||||||
|
if (err != EAGAIN) {
|
||||||
|
print("sock error %s!", err);
|
||||||
|
on_send_finish(socket, IOStatus.error, 0, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
if (mode == IOMode.immediate) {
|
||||||
|
on_send_finish(socket, IOStatus.wouldBlock, 0, null);
|
||||||
|
} else {
|
||||||
|
with (m_fds[socket]) {
|
||||||
|
writeCallback = () @trusted { return cast(IOCallback)on_send_finish; } ();
|
||||||
|
writeMode = mode;
|
||||||
|
bytesWritten = 0;
|
||||||
|
writeBuffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNotifyCallback!(EventType.write)(socket, &onDgramWrite);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
on_send_finish(socket, IOStatus.ok, ret, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancelSend(DatagramSocketFD socket)
|
||||||
|
{
|
||||||
|
assert(m_fds[socket].writeCallback !is null, "Cancelling write when there is no write in progress.");
|
||||||
|
setNotifyCallback!(EventType.write)(socket, null);
|
||||||
|
m_fds[socket].writeBuffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDgramWrite(FD fd)
|
||||||
|
{
|
||||||
|
auto slot = &m_fds[fd];
|
||||||
|
auto socket = cast(DatagramSocketFD)fd;
|
||||||
|
|
||||||
|
sizediff_t ret;
|
||||||
|
if (slot.targetAddr) {
|
||||||
|
() @trusted { ret = .sendto(socket, slot.writeBuffer.ptr, slot.writeBuffer.length, 0, slot.targetAddr.name, slot.targetAddr.nameLen); } ();
|
||||||
|
} else {
|
||||||
|
() @trusted { ret = .send(socket, slot.writeBuffer.ptr, slot.writeBuffer.length, 0); } ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
auto err = getSocketError();
|
||||||
|
if (err != EAGAIN) {
|
||||||
|
setNotifyCallback!(EventType.write)(socket, null);
|
||||||
|
() @trusted { return cast(DatagramIOCallback)slot.writeCallback; } ()(socket, IOStatus.error, 0, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setNotifyCallback!(EventType.write)(socket, null);
|
||||||
|
() @trusted { return cast(DatagramIOCallback)slot.writeCallback; } ()(socket, IOStatus.ok, ret, null);
|
||||||
|
}
|
||||||
|
|
||||||
final override void addRef(SocketFD fd)
|
final override void addRef(SocketFD fd)
|
||||||
{
|
{
|
||||||
auto pfd = &m_fds[fd];
|
auto pfd = &m_fds[fd];
|
||||||
|
@ -695,10 +854,10 @@ abstract class PosixEventDriver : EventDriver,
|
||||||
m_fds[fd].callback[evt] = callback;
|
m_fds[fd].callback[evt] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SocketFD createSocket(AddressFamily family)
|
private SocketFD createSocket(AddressFamily family, int type)
|
||||||
{
|
{
|
||||||
int sock;
|
int sock;
|
||||||
() @trusted { sock = socket(family, SOCK_STREAM, 0); } ();
|
() @trusted { sock = socket(family, type, 0); } ();
|
||||||
if (sock == -1) return SocketFD.invalid;
|
if (sock == -1) return SocketFD.invalid;
|
||||||
setSocketNonBlocking(cast(SocketFD)sock);
|
setSocketNonBlocking(cast(SocketFD)sock);
|
||||||
return cast(SocketFD)sock;
|
return cast(SocketFD)sock;
|
||||||
|
@ -733,12 +892,13 @@ private struct FDSlot {
|
||||||
size_t bytesRead;
|
size_t bytesRead;
|
||||||
ubyte[] readBuffer;
|
ubyte[] readBuffer;
|
||||||
IOMode readMode;
|
IOMode readMode;
|
||||||
IOCallback readCallback;
|
IOCallback readCallback; // FIXME: this type only works for stream sockets
|
||||||
|
|
||||||
size_t bytesWritten;
|
size_t bytesWritten;
|
||||||
const(ubyte)[] writeBuffer;
|
const(ubyte)[] writeBuffer;
|
||||||
IOMode writeMode;
|
IOMode writeMode;
|
||||||
IOCallback writeCallback;
|
IOCallback writeCallback; // FIXME: this type only works for stream sockets
|
||||||
|
Address targetAddr;
|
||||||
|
|
||||||
ConnectCallback connectCallback;
|
ConnectCallback connectCallback;
|
||||||
AcceptCallback acceptCallback;
|
AcceptCallback acceptCallback;
|
||||||
|
|
Loading…
Reference in a new issue