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