1 module hunt.io.channel.iocp.AbstractDatagramSocket; 2 3 // dfmt off 4 version (HAVE_IOCP) : 5 // dfmt on 6 7 // import hunt.io.ByteBuffer; 8 // import hunt.io.BufferUtils; 9 import hunt.event.selector.Selector; 10 import hunt.io.channel.AbstractSocketChannel; 11 import hunt.io.channel.Common; 12 import hunt.io.channel.iocp.Common; 13 import hunt.logging; 14 import hunt.Functions; 15 16 // import hunt.util.ThreadHelper; 17 18 // import core.atomic; 19 import core.sys.windows.windows; 20 import core.sys.windows.winsock2; 21 import core.sys.windows.mswsock; 22 23 // import std.conv; 24 // import std.exception; 25 // import std.format; 26 // import std.process; 27 import std.socket; 28 29 // import std.stdio; 30 31 /** 32 UDP Socket 33 */ 34 abstract class AbstractDatagramSocket : AbstractSocketChannel { 35 /// Constructs a blocking IPv4 UDP Socket. 36 this(Selector loop, AddressFamily family = AddressFamily.INET) { 37 super(loop, ChannelType.UDP); 38 setFlag(ChannelFlag.Read, true); 39 // setFlag(ChannelFlag.ETMode, false); 40 41 this.socket = new UdpSocket(family); 42 _readBuffer = new UdpDataObject(); 43 _readBuffer.data = new ubyte[4096 * 2]; 44 45 if (family == AddressFamily.INET) 46 _bindAddress = new InternetAddress(InternetAddress.PORT_ANY); 47 else if (family == AddressFamily.INET6) 48 _bindAddress = new Internet6Address(Internet6Address.PORT_ANY); 49 else 50 _bindAddress = new UnknownAddress(); 51 } 52 53 final void bind(Address addr) { 54 if (_binded) 55 return; 56 _bindAddress = addr; 57 socket.bind(_bindAddress); 58 _binded = true; 59 } 60 61 final bool isBind() { 62 return _binded; 63 } 64 65 Address bindAddr() { 66 return _bindAddress; 67 } 68 69 override void start() { 70 if (!_binded) { 71 socket.bind(_bindAddress); 72 _binded = true; 73 } 74 } 75 76 // abstract void doRead(); 77 78 private UdpDataObject _readBuffer; 79 protected bool _binded = false; 80 protected Address _bindAddress; 81 82 mixin CheckIocpError; 83 84 void doRead() { 85 version (HUNT_IO_DEBUG) 86 trace("Receiving......"); 87 88 _dataReadBuffer.len = cast(uint) _readBuffer.data.length; 89 _dataReadBuffer.buf = cast(char*) _readBuffer.data.ptr; 90 _iocpread.channel = this; 91 _iocpread.operation = IocpOperation.read; 92 remoteAddrLen = cast(int) bindAddr().nameLen(); 93 94 DWORD dwReceived = 0; 95 DWORD dwFlags = 0; 96 97 int nRet = WSARecvFrom(cast(SOCKET) this.handle, &_dataReadBuffer, 98 cast(uint) 1, &dwReceived, &dwFlags, cast(SOCKADDR*)&remoteAddr, &remoteAddrLen, 99 &_iocpread.overlapped, cast(LPWSAOVERLAPPED_COMPLETION_ROUTINE) null); 100 checkErro(nRet, SOCKET_ERROR); 101 } 102 103 Address buildAddress() { 104 Address tmpaddr; 105 if (remoteAddrLen == 32) { 106 sockaddr_in* addr = cast(sockaddr_in*)(&remoteAddr); 107 tmpaddr = new InternetAddress(*addr); 108 } else { 109 sockaddr_in6* addr = cast(sockaddr_in6*)(&remoteAddr); 110 tmpaddr = new Internet6Address(*addr); 111 } 112 return tmpaddr; 113 } 114 115 bool tryRead(scope SimpleActionHandler read) { 116 this.clearError(); 117 if (this.readLen == 0) { 118 read(null); 119 } else { 120 ubyte[] data = this._readBuffer.data; 121 this._readBuffer.data = data[0 .. this.readLen]; 122 this._readBuffer.addr = this.buildAddress(); 123 scope (exit) 124 this._readBuffer.data = data; 125 read(this._readBuffer); 126 this._readBuffer.data = data; 127 if (this.isRegistered) 128 this.doRead(); 129 } 130 return false; 131 } 132 133 IocpContext _iocpread; 134 WSABUF _dataReadBuffer; 135 136 sockaddr remoteAddr; 137 int remoteAddrLen; 138 139 }