1 /*
2  * Geario - A cross-platform abstraction library with asynchronous I/O.
3  *
4  * Copyright (C) 2021-2022 Kerisy.com
5  *
6  * Website: https://www.kerisy.com
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module geario.net.UdpSocket;
13 
14 import geario.event;
15 import geario.logging;
16 
17 import std.socket;
18 import std.exception;
19 
20 /**
21 */
22 class UdpSocket : AbstractDatagramSocket {
23 
24     private UdpDataHandler _receivedHandler;
25 
26     this(EventLoop loop, AddressFamily amily = AddressFamily.INET) {
27         super(loop, amily);
28     }
29     
30     UdpSocket enableBroadcast(bool flag) {
31         this.socket.setOption(SocketOptionLevel.SOCKET, SocketOption.BROADCAST, flag);
32         return this;
33     }
34 
35     UdpSocket onReceived(UdpDataHandler handler) {
36         _receivedHandler = handler;
37         return this;
38     }
39 
40     ptrdiff_t sendTo(const(void)[] buf, Address to) {
41         return this.socket.sendTo(buf, to);
42     }
43 
44     ptrdiff_t sendTo(const(void)[] buf) {
45         return this.socket.sendTo(buf);
46     }
47 
48     ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags, Address to) {
49         return this.socket.sendTo(buf, flags, to);
50     }
51 
52     UdpSocket Bind(string ip, ushort port) {
53         super.Bind(parseAddress(ip, port));
54         return this;
55     }
56 
57     UdpSocket Bind(Address address) {
58         super.Bind(address);
59         return this;
60     }
61 
62     UdpSocket Connect(Address addr) {
63         this.socket.connect(addr);
64         return this;
65     }
66 
67     override void Start() {
68         if (!_binded) {
69             socket.bind(_bindAddress);
70             _binded = true;
71         }
72 
73         _loop.Register(this);
74         _isRegistered = true;
75         version (HAVE_IOCP)
76             DoRead();
77     }
78 
79     protected override void OnRead() {
80         bool canRead = true;
81         while (canRead && _isRegistered) {
82             version (GEAR_IO_DEBUG)
83                 log.trace("reading data...");
84             canRead = tryRead((Object obj) {
85                 collectException(() {
86                     UdpDataObject data = cast(UdpDataObject) obj;
87                     if (data !is null) {
88                         _receivedHandler(data.data, data.addr);
89                     }
90                 }());
91             });
92 
93             if (this.IsError) {
94                 canRead = false;
95                 this.Close();
96                 log.error("UDP socket Error: ", this.ErrorMessage);
97             }
98         }
99     }
100 
101 }