1 /************************************************************************
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
32 /* create a new udp client connection */
33 net_connection_t
*udp_client_connect(char* host
, char* port
)
35 net_connection_t
*n
= net_connection();
36 n
->type
= NETTYPE_UDP
;
37 n
->host
= strdup(host
);
38 n
->port
= strdup(port
);
40 udp_client_reconnect(n
);
45 /* reconnect a close udp connection */
46 int udp_client_reconnect(net_connection_t
*n
)
48 int max_retries
= config_get_int("net.max_retries");
51 if (n
->state
== NETSTATE_OPEN
|| n
->tries
> max_retries
)
56 if (n
->state
== NETSTATE_UNUSED
) {
57 int f
= config_get_int("net.ipv4");
58 int s
= config_get_int("net.ipv6");
59 memset(&n
->hints
, 0, sizeof(n
->hints
));
61 n
->hints
.ai_family
= AF_UNSPEC
;
63 n
->hints
.ai_family
= AF_INET6
;
65 n
->hints
.ai_family
= AF_INET
;
67 n
->hints
.ai_socktype
= SOCK_DGRAM
;
69 /* resolve hostname */
70 if (getaddrinfo(n
->host
, n
->port
, &n
->hints
, &n
->addr
)) {
71 vlprintf(CN_ERROR
, "Unable to resolve host '%s'",n
->host
);
75 n
->state
= NETSTATE_CLOSED
;
79 if ((n
->fd
= socket(n
->addr
->ai_family
, n
->addr
->ai_socktype
, n
->addr
->ai_protocol
)) == -1) {
80 vlprintf(CN_ERROR
, "Unable to reconnect to host %s",n
->host
);
84 /* connect to server */
85 if (connect(n
->fd
, n
->addr
->ai_addr
, n
->addr
->ai_addrlen
)) {
87 vlprintf(CN_ERROR
, "Unable to reconnect to host %s",n
->host
);
91 n
->state
= NETSTATE_OPEN
;
97 /* create a new udp server connection */
98 net_connection_t
*udp_host_connect(char* host
, char* port
)
100 net_connection_t
*n
= net_connection();
104 n
->type
= NETTYPE_UDP_HOST
;
106 n
->host
= strdup(host
);
107 n
->port
= strdup(port
);
108 n
->peers
= array_create(ARRAY_TYPE_PTR
);
110 if (udp_host_reconnect(n
)) {
118 /* start listening for udp clients */
119 int udp_host_reconnect(net_connection_t
*n
)
121 int max_retries
= config_get_int("net.max_retries");
124 if (n
->state
== NETSTATE_OPEN
|| n
->tries
> max_retries
)
129 if (n
->state
== NETSTATE_UNUSED
) {
131 int f
= config_get_int("net.ipv4");
132 int s
= config_get_int("net.ipv6");
134 memset(&n
->hints
, 0, sizeof(n
->hints
));
136 n
->hints
.ai_family
= AF_UNSPEC
;
138 n
->hints
.ai_family
= AF_INET6
;
140 n
->hints
.ai_family
= AF_INET
;
142 n
->hints
.ai_socktype
= SOCK_DGRAM
;
143 n
->hints
.ai_flags
= AI_PASSIVE
;
145 if (strcmp(n
->host
,"*"))
148 /* resolve hostname */
149 if (getaddrinfo(nhost
, n
->port
, &n
->hints
, &n
->addr
)) {
150 vlprintf(CN_ERROR
, "Unable to resolve host '%s'",n
->host
);
154 n
->state
= NETSTATE_CLOSED
;
158 if ((n
->fd
= socket(n
->hints
.ai_family
, n
->hints
.ai_socktype
, n
->hints
.ai_protocol
)) == -1) {
159 vlprintf(CN_ERROR
, "Unable to open port %u",n
->port
);
162 /* bind to the socket */
163 if ((bind(n
->fd
, n
->addr
->ai_addr
,sizeof(*n
->addr
->ai_addr
))) < 0) {
164 vlprintf(CN_ERROR
, "Unable to bind port %u",n
->port
);
168 n
->state
= NETSTATE_OPEN
;
174 /* write data to a udp connection */
175 int udp_write(net_connection_t
*n
, void *buff
, unsigned int size
)
178 if (n
->state
== NETSTATE_OPEN
) {
180 if (n
->type
== NETTYPE_UDP_HOST
) {
181 r
= (int)sendto(n
->fd
, buff
, size
, 0, (struct sockaddr
*)&n
->remote_addr
, n
->remote_addr_len
);
183 r
= (int)write(n
->fd
,buff
,size
);
186 vlprintf(CN_ERROR
, "failed to write to connection %d (%d)",n
->fd
,errno
);
187 if (n
->type
!= NETTYPE_UDP_HOST
)
189 n
->state
= NETSTATE_CLOSED
;
195 static int udp_process(net_connection_t
*n
)
201 if (n
->type
== NETTYPE_UDP_HOST
) {
202 l
= recvfrom(n
->fd
, buff
, 2048, 0, (struct sockaddr
*)&n
->remote_addr
, &n
->remote_addr_len
);
204 l
= (int)recv(n
->fd
,buff
,2048,0);
209 if (errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
210 if (n
->type
!= NETTYPE_UDP_HOST
)
212 n
->state
= NETSTATE_CLOSED
;
215 if (n
->type
!= NETTYPE_UDP_HOST
)
217 n
->state
= NETSTATE_CLOSED
;
220 file_t
*f
= file_create(NULL
,NULL
);
221 file_write(f
,buff
,l
);
222 n
->buff
.udp
.unsorted
= list_push(&n
->buff
.udp
.unsorted
,f
);
225 /* TODO: sort the unsorted packets */
230 /* discards the current packet buffer, and returns a pointer to the next packet buffer */
231 file_t
*udp_next(net_connection_t
*n
)
234 if (n
->state
!= NETSTATE_OPEN
)
239 if (!n
->buff
.udp
.sorted
)
242 f
= list_pull(&n
->buff
.udp
.sorted
);
246 return n
->buff
.udp
.sorted
;
249 /* gets a pointer to the current packet buffer */
250 file_t
*udp_current(net_connection_t
*n
)
252 if (n
->state
!= NETSTATE_OPEN
)
257 return n
->buff
.udp
.sorted
;
260 /* determine if data is pending on a udp connection */
261 int udp_pending(net_connection_t
*n
)
263 if (n
->state
!= NETSTATE_OPEN
)
270 /* read data from a udp connection */
271 int udp_read(net_connection_t
*n
, void *buff
, unsigned int size
)
280 l
= file_read(b
,buff
,size
);
288 return file_read(b
,buff
,size
);
291 /* read a line from a udp connection */
292 int udp_readline(net_connection_t
*n
, void *buff
, unsigned int size
)
301 l
= file_readline(b
,buff
,size
);
309 return file_readline(b
,buff
,size
);
312 /* broadcast data to all peers of a udp host connection */
313 int udp_broadcast(net_connection_t
*n
, void *buff
, unsigned int size
)
316 net_connection_t
**p
;
317 if (!n
|| n
->state
!= NETSTATE_OPEN
|| !n
->peers
|| !n
->peers
->length
)
321 for (i
=0; i
<n
->peers
->length
; i
++) {
324 udp_write(p
[i
],buff
,size
);
330 /* accept new connections to a udp host */
331 int udp_accept(net_connection_t
*n
)
334 struct sockaddr_in
*s4
[2];
335 struct sockaddr_in6
*s6
[2];
338 array_t
*a
= net_select(0,0,n
);
347 c
= net_connection();
349 c
->state
= NETSTATE_OPEN
;
351 c
->buff
.udp
.unsorted
= NULL
;
352 c
->buff
.udp
.sorted
= NULL
;
354 l
= recvfrom(n
->fd
, buff
, 2048, 0, (struct sockaddr
*)&c
->remote_addr
, &c
->remote_addr_len
);
358 net_connection_t
**p
= n
->peers
->data
;
359 file_t
*f
= file_create(NULL
,NULL
);
360 file_write(f
,buff
,l
);
361 c
->buff
.udp
.unsorted
= list_push(&c
->buff
.udp
.unsorted
,f
);
362 for (i
=0; i
<n
->peers
->length
; i
++) {
363 if (p
[i
] && c
->remote_addr
.ss_family
== p
[i
]->remote_addr
.ss_family
) {
364 if (c
->remote_addr
.ss_family
== AF_INET
) {
365 s4
[0] = (struct sockaddr_in
*)&c
->remote_addr
;
366 s4
[1] = (struct sockaddr_in
*)&p
[i
]->remote_addr
;
367 if (s4
[0]->sin_addr
.s_addr
== s4
[1]->sin_addr
.s_addr
) {
372 }else if (c
->remote_addr
.ss_family
== AF_INET6
) {
373 s6
[0] = (struct sockaddr_in6
*)&c
->remote_addr
;
374 s6
[1] = (struct sockaddr_in6
*)&p
[i
]->remote_addr
;
375 if (!memcmp(s6
[0]->sin6_addr
.s6_addr
,s6
[1]->sin6_addr
.s6_addr
,16)) {
383 for (i
=0; i
<n
->peers
->length
; i
++) {
389 array_push_ptr(n
->peers
,c
);
390 return n
->peers
->length
-1;