1 |
1 |
2 #include "UDP.hh" |
2 #include "UDP.hh" |
|
3 #include "../Engine.hh" |
3 |
4 |
4 #include <ClanLib/core.h> |
5 #include <ClanLib/core.h> |
5 #include <cassert> |
6 #include <cassert> |
6 |
7 |
7 NetworkUDP::NetworkUDP (void) : |
8 NetworkUDP::NetworkUDP (void) : |
8 socket(CL_Socket::udp, CL_Socket::ipv4) { |
9 socket(AF_UNSPEC, SOCK_DGRAM) |
9 |
10 { |
10 // do not bind |
11 // do not bind |
11 |
12 |
12 // connect signal |
13 // connect signal |
13 slots.connect(socket.sig_read_triggered(), this, &NetworkUDP::on_recv); |
14 slots.connect(socket.sig_read(), this, &NetworkUDP::on_recv); |
14 |
15 |
15 // nonblocking |
16 // nonblocking |
16 socket.set_nonblocking(true); |
17 socket.set_nonblocking(true); |
17 } |
18 } |
18 |
19 |
19 NetworkUDP::NetworkUDP (const NetworkAddress &bind_addr) : |
20 NetworkUDP::NetworkUDP (const NetworkAddress &bind_addr) : |
20 socket(CL_Socket::udp, CL_Socket::ipv4) { |
21 socket(AF_UNSPEC, SOCK_DGRAM) { |
21 |
22 |
22 // bind socket |
23 // bind socket |
23 socket.bind(bind_addr); |
24 socket.bind(bind_addr); |
24 |
25 |
25 // connect signal |
26 // connect signal |
26 slots.connect(socket.sig_read_triggered(), this, &NetworkUDP::on_recv); |
27 slots.connect(socket.sig_read(), this, &NetworkUDP::on_recv); |
27 |
28 |
28 // nonblocking |
29 // nonblocking |
29 socket.set_nonblocking(true); |
30 socket.set_nonblocking(true); |
30 } |
31 } |
31 |
32 |
32 void NetworkUDP::on_recv (void) { |
33 void NetworkUDP::on_recv (void) { |
33 int ret; |
34 size_t ret; |
34 NetworkPacket pkt; |
35 NetworkPacket pkt; |
35 NetworkAddress src; |
36 NetworkAddress src; |
36 |
37 |
37 // receieve as many packets as possible |
38 // receieve as many packets as possible |
38 do { |
39 do { |
39 // attempt to recv a packet |
40 // attempt to recv a packet |
40 try { |
41 ret = socket.recv(pkt.get_buf(), pkt.get_buf_size(), &src); |
41 ret = socket.recv(pkt.get_buf(), pkt.get_buf_size(), src); |
42 |
|
43 // no more packets? |
|
44 if (ret == 0) |
|
45 return; |
42 |
46 |
43 } catch (CL_Error &e) { |
|
44 if (errno == EAGAIN) |
|
45 return; |
|
46 else |
|
47 throw; |
|
48 } |
|
49 |
|
50 // set packet data size |
47 // set packet data size |
51 pkt.set_data_size(ret); |
48 pkt.set_data_size(ret); |
52 |
49 |
53 // handle packet |
50 // handle packet |
54 _sig_packet(pkt, src); |
51 _sig_packet(pkt, src); |
55 |
52 |
56 } while (true); |
53 } while (true); |
57 } |
54 } |
58 |
55 |
59 bool NetworkUDP::sendto (const NetworkPacketBuffer &packet, const NetworkAddress &dst) { |
56 bool NetworkUDP::sendto (const NetworkPacketBuffer &packet, const NetworkAddress &dst) { |
60 int ret; |
57 size_t ret; |
61 |
58 |
62 // XXX: shouldn't get trimmed |
|
63 try { |
59 try { |
64 ret = socket.send(packet.get_buf(), packet.get_data_size(), dst); |
60 // try and send |
|
61 ret = socket.send(packet.get_buf(), packet.get_data_size(), &dst); |
65 |
62 |
66 } catch (CL_Error &e) { |
63 } catch (NetworkSocketError &e) { |
67 // XXX: catch some errors, but not others? |
64 // catch and log errors |
|
65 Engine::log(WARN, "udp.sendto") << "socket->send raised error: " << e.what(); |
68 return false; |
66 return false; |
69 } |
67 } |
|
68 |
|
69 // weird packet size? |
|
70 if (ret != packet.get_data_size()) { |
|
71 Engine::log(ERROR, "udp.sendto") << "socket->send returned weird length: " << ret << ", packet was " << packet.get_data_size(); |
|
72 return false; |
70 |
73 |
71 assert(ret > 0); |
74 } else { |
72 |
75 // sent |
73 // UDP shouldn't trim packets |
76 return true; |
74 assert((unsigned int) ret == packet.get_data_size()); |
77 } |
75 |
|
76 // good |
|
77 return true; |
|
78 } |
78 } |
79 |
79 |