]> git.lizzy.rs Git - minetest.git/blob - src/socket.cpp
plant amount fix and ravine amount setting
[minetest.git] / src / socket.cpp
1 #include "socket.h"
2 #include "debug.h"
3 #include <stdio.h>
4 #include <iostream>
5 #include <stdlib.h>
6 #include <errno.h>
7
8 // Debug printing options
9 #define DP 0
10 #define DPS ""
11
12 bool g_sockets_initialized = false;
13
14 void sockets_init()
15 {
16 #ifdef _WIN32
17         WSADATA WsaData;
18         if(WSAStartup( MAKEWORD(2,2), &WsaData ) != NO_ERROR)
19                 throw SocketException("WSAStartup failed");
20 #else
21 #endif
22         g_sockets_initialized = true;
23 }
24
25 void sockets_cleanup()
26 {
27 #ifdef _WIN32
28         WSACleanup();
29 #endif
30 }
31
32 Address::Address()
33 {
34 }
35
36 Address::Address(unsigned int address, unsigned short port)
37 {
38         m_address = address;
39         m_port = port;
40 }
41
42 Address::Address(unsigned int a, unsigned int b,
43                 unsigned int c, unsigned int d,
44                 unsigned short port)
45 {
46         m_address = (a<<24) | (b<<16) | ( c<<8) | d;
47         m_port = port;
48 }
49
50 bool Address::operator==(Address &address)
51 {
52         return (m_address == address.m_address
53                         && m_port == address.m_port);
54 }
55
56 bool Address::operator!=(Address &address)
57 {
58         return !(*this == address);
59 }
60
61 void Address::Resolve(const char *name)
62 {
63         struct addrinfo *resolved;
64         int e = getaddrinfo(name, NULL, NULL, &resolved);
65         if(e != 0)
66                 throw ResolveError("");
67         /*
68                 FIXME: This is an ugly hack; change the whole class
69                 to store the address as sockaddr
70         */
71         struct sockaddr_in *t = (struct sockaddr_in*)resolved->ai_addr;
72         m_address = ntohl(t->sin_addr.s_addr);
73         freeaddrinfo(resolved);
74 }
75
76 unsigned int Address::getAddress() const
77 {
78         return m_address;
79 }
80
81 unsigned short Address::getPort() const
82 {
83         return m_port;
84 }
85
86 void Address::setAddress(unsigned int address)
87 {
88         m_address = address;
89 }
90
91 void Address::setPort(unsigned short port)
92 {
93         m_port = port;
94 }
95
96 void Address::print(std::ostream *s) const
97 {
98         (*s)<<((m_address>>24)&0xff)<<"."
99                         <<((m_address>>16)&0xff)<<"."
100                         <<((m_address>>8)&0xff)<<"."
101                         <<((m_address>>0)&0xff)<<":"
102                         <<m_port;
103 }
104
105 void Address::print() const
106 {
107         print(&dstream);
108 }
109
110 UDPSocket::UDPSocket()
111 {
112         if(g_sockets_initialized == false)
113                 throw SocketException("Sockets not initialized");
114         
115     m_handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
116         
117         if(DP)
118         dstream<<DPS<<"UDPSocket("<<(int)m_handle<<")::UDPSocket()"<<std::endl;
119         
120     if(m_handle <= 0)
121     {
122                 throw SocketException("Failed to create socket");
123     }
124
125 /*#ifdef _WIN32
126         DWORD nonblocking = 0;
127         if(ioctlsocket(m_handle, FIONBIO, &nonblocking) != 0)
128         {
129                 throw SocketException("Failed set non-blocking mode");
130         }
131 #else
132         int nonblocking = 0;
133         if(fcntl(m_handle, F_SETFL, O_NONBLOCK, nonblocking) == -1)
134         {
135                 throw SocketException("Failed set non-blocking mode");
136         }
137 #endif*/
138
139         setTimeoutMs(0);
140 }
141
142 UDPSocket::~UDPSocket()
143 {
144         if(DP)
145         dstream<<DPS<<"UDPSocket("<<(int)m_handle<<")::~UDPSocket()"<<std::endl;
146
147 #ifdef _WIN32
148         closesocket(m_handle);
149 #else
150         close(m_handle);
151 #endif
152 }
153
154 void UDPSocket::Bind(unsigned short port)
155 {
156         if(DP)
157         dstream<<DPS<<"UDPSocket("<<(int)m_handle
158                         <<")::Bind(): port="<<port<<std::endl;
159
160     sockaddr_in address;
161     address.sin_family = AF_INET;
162     address.sin_addr.s_addr = INADDR_ANY;
163     address.sin_port = htons(port);
164
165     if(bind(m_handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
166     {
167 #ifndef DISABLE_ERRNO
168                 dstream<<(int)m_handle<<": Bind failed: "<<strerror(errno)<<std::endl;
169 #endif
170                 throw SocketException("Failed to bind socket");
171     }
172 }
173
174 void UDPSocket::Send(const Address & destination, const void * data, int size)
175 {
176         bool dumping_packet = false;
177         if(INTERNET_SIMULATOR)
178                 dumping_packet = (rand()%10==0); //easy
179                 //dumping_packet = (rand()%4==0); // hard
180
181         if(DP){
182                 /*dstream<<DPS<<"UDPSocket("<<(int)m_handle
183                                 <<")::Send(): destination=";*/
184                 dstream<<DPS;
185                 dstream<<(int)m_handle<<" -> ";
186                 destination.print();
187                 dstream<<", size="<<size<<", data=";
188                 for(int i=0; i<size && i<20; i++){
189                         if(i%2==0) printf(" ");
190                         DEBUGPRINT("%.2X", ((int)((const char*)data)[i])&0xff);
191                 }
192                 if(size>20)
193                         dstream<<"...";
194                 if(dumping_packet)
195                         dstream<<" (DUMPED BY INTERNET_SIMULATOR)";
196                 dstream<<std::endl;
197         }
198         else if(dumping_packet)
199         {
200                 // Lol let's forget it
201                 dstream<<"UDPSocket::Send(): "
202                                 "INTERNET_SIMULATOR: dumping packet."
203                                 <<std::endl;
204         }
205
206         if(dumping_packet)
207                 return;
208
209         sockaddr_in address;
210         address.sin_family = AF_INET;
211         address.sin_addr.s_addr = htonl(destination.getAddress());
212         address.sin_port = htons(destination.getPort());
213
214         int sent = sendto(m_handle, (const char*)data, size,
215                 0, (sockaddr*)&address, sizeof(sockaddr_in));
216
217     if(sent != size)
218     {
219                 throw SendFailedException("Failed to send packet");
220     }
221 }
222
223 int UDPSocket::Receive(Address & sender, void * data, int size)
224 {
225         if(WaitData(m_timeout_ms) == false)
226         {
227                 return -1;
228         }
229
230         sockaddr_in address;
231         socklen_t address_len = sizeof(address);
232
233         int received = recvfrom(m_handle, (char*)data,
234                         size, 0, (sockaddr*)&address, &address_len);
235
236         if(received < 0)
237                 return -1;
238
239         unsigned int address_ip = ntohl(address.sin_addr.s_addr);
240         unsigned int address_port = ntohs(address.sin_port);
241
242         sender = Address(address_ip, address_port);
243
244         if(DP){
245                 //dstream<<DPS<<"UDPSocket("<<(int)m_handle<<")::Receive(): sender=";
246                 dstream<<DPS<<(int)m_handle<<" <- ";
247                 sender.print();
248                 //dstream<<", received="<<received<<std::endl;
249                 dstream<<", size="<<received<<", data=";
250                 for(int i=0; i<received && i<20; i++){
251                         if(i%2==0) printf(" ");
252                         DEBUGPRINT("%.2X", ((int)((const char*)data)[i])&0xff);
253                 }
254                 if(received>20)
255                         dstream<<"...";
256                 dstream<<std::endl;
257         }
258
259         return received;
260 }
261
262 int UDPSocket::GetHandle()
263 {
264         return m_handle;
265 }
266
267 void UDPSocket::setTimeoutMs(int timeout_ms)
268 {
269         m_timeout_ms = timeout_ms;
270 }
271
272 bool UDPSocket::WaitData(int timeout_ms)
273 {
274         fd_set readset;
275         int result;
276
277         // Initialize the set
278         FD_ZERO(&readset);
279         FD_SET(m_handle, &readset);
280
281         // Initialize time out struct
282         struct timeval tv;
283         tv.tv_sec = 0;
284         tv.tv_usec = timeout_ms * 1000;
285         // select()
286         result = select(m_handle+1, &readset, NULL, NULL, &tv);
287
288         if(result == 0){
289                 // Timeout
290                 /*dstream<<"Select timed out (timeout_ms="
291                                 <<timeout_ms<<")"<<std::endl;*/
292                 return false;
293         }
294         else if(result < 0){
295                 // Error
296 #ifndef DISABLE_ERRNO
297                 dstream<<(int)m_handle<<": Select failed: "<<strerror(errno)<<std::endl;
298 #endif
299 #ifdef _WIN32
300                 dstream<<(int)m_handle<<": WSAGetLastError()="<<WSAGetLastError()<<std::endl;
301 #endif
302                 throw SocketException("Select failed");
303         }
304         else if(FD_ISSET(m_handle, &readset) == false){
305                 // No data
306                 //dstream<<"Select reported no data in m_handle"<<std::endl;
307                 return false;
308         }
309         
310         // There is data
311         //dstream<<"Select reported data in m_handle"<<std::endl;
312         return true;
313 }
314
315