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 }