1 /*
2  * Copyright (c) 2012 Hypertriton, Inc. <http://hypertriton.com/>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23  * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 /*
27  * Network access interface.
28  */
29 
30 #include <agar/core/core.h>
31 
32 const char *agNetAddrFamilyNames[] = {
33 	"none",
34 	"local",
35 	"inet4",
36 	"inet6"
37 };
38 const char *agNetSocketTypeNames[] = {
39 	"none",
40 	"stream",
41 	"dgram",
42 	"raw",
43 	"rdm",
44 	"seqpacket"
45 };
46 
47 const AG_NetOps *agNetOps = NULL;
48 
49 /* Create a new, unconnected socket. */
50 AG_NetSocket *
AG_NetSocketNew(enum ag_net_addr_family af,enum ag_net_socket_type type,int proto)51 AG_NetSocketNew(enum ag_net_addr_family af, enum ag_net_socket_type type,
52     int proto)
53 {
54 	AG_NetSocket *ns;
55 
56 	if ((ns = TryMalloc(sizeof(AG_NetSocket))) == NULL) {
57 		return (NULL);
58 	}
59 	ns->family = af;
60 	ns->type = type;
61 	ns->proto = proto;
62 	ns->flags = 0;
63 	ns->poll = 0;
64 	ns->addrLocal = NULL;
65 	ns->addrRemote = NULL;
66 	ns->fd = -1;
67 	ns->listenBacklog = 10;
68 	ns->p = NULL;
69 
70 	if (agNetOps->initSocket != NULL &&
71 	    agNetOps->initSocket(ns) == -1) {
72 		free(ns);
73 		return (NULL);
74 	}
75 	AG_MutexInitRecursive(&ns->lock);
76 	return (ns);
77 }
78 
79 void
AG_NetSocketFree(AG_NetSocket * ns)80 AG_NetSocketFree(AG_NetSocket *ns)
81 {
82 	if (agNetOps->destroySocket != NULL) {
83 		agNetOps->destroySocket(ns);
84 	}
85 	if (ns->addrLocal != NULL) { AG_NetAddrFree(ns->addrLocal); }
86 	if (ns->addrRemote != NULL) { AG_NetAddrFree(ns->addrRemote); }
87 	AG_MutexDestroy(&ns->lock);
88 	free(ns);
89 }
90 
91 /* Allocate a new socket set. */
92 void
AG_NetSocketSetInit(AG_NetSocketSet * nss)93 AG_NetSocketSetInit(AG_NetSocketSet *nss)
94 {
95 	TAILQ_INIT(nss);
96 }
97 
98 /* Clear a network socket set. */
99 void
AG_NetSocketSetClear(AG_NetSocketSet * nss)100 AG_NetSocketSetClear(AG_NetSocketSet *nss)
101 {
102 	AG_NetSocket *ns, *nsNext;
103 
104 	for (ns = TAILQ_FIRST(nss);
105 	     ns != TAILQ_END(nss);
106 	     ns = nsNext) {
107 		nsNext = TAILQ_NEXT(ns, sockets);
108 		AG_NetSocketFree(ns);
109 	}
110 	TAILQ_INIT(nss);
111 }
112 
113 /* Allocate a new network address list. */
114 AG_NetAddrList *
AG_NetAddrListNew(void)115 AG_NetAddrListNew(void)
116 {
117 	AG_NetAddrList *nal;
118 
119 	if ((nal = TryMalloc(sizeof(AG_NetAddrList))) == NULL) {
120 		return (NULL);
121 	}
122 	TAILQ_INIT(nal);
123 	return (nal);
124 }
125 
126 /* Clear a network address list. */
127 void
AG_NetAddrListClear(AG_NetAddrList * nal)128 AG_NetAddrListClear(AG_NetAddrList *nal)
129 {
130 	AG_NetAddr *addr, *addrNext;
131 
132 	for (addr = TAILQ_FIRST(nal);
133 	     addr != TAILQ_END(nal);
134 	     addr = addrNext) {
135 		addrNext = TAILQ_NEXT(addr, addrs);
136 		AG_NetAddrFree(addr);
137 	}
138 	TAILQ_INIT(nal);
139 }
140 
141 /* Free a network address list. */
142 void
AG_NetAddrListFree(AG_NetAddrList * nal)143 AG_NetAddrListFree(AG_NetAddrList *nal)
144 {
145 	AG_NetAddrListClear(nal);
146 	free(nal);
147 }
148 
149 /* Allocate a new network address. */
150 AG_NetAddr *
AG_NetAddrNew(void)151 AG_NetAddrNew(void)
152 {
153 	AG_NetAddr *addr;
154 
155 	if ((addr = TryMalloc(sizeof(AG_NetAddr))) == NULL) {
156 		return (NULL);
157 	}
158 	addr->family = AG_NET_AF_NONE;
159 	addr->port = 0;
160 	addr->sNum = NULL;
161 	addr->sName = NULL;
162 	return (addr);
163 }
164 
165 void
AG_NetAddrFree(AG_NetAddr * na)166 AG_NetAddrFree(AG_NetAddr *na)
167 {
168 	if (na->family == AG_NET_LOCAL) {
169 		Free(na->na_local.path);
170 	}
171 	Free(na->sNum);
172 	Free(na->sName);
173 	free(na);
174 }
175 
176 /* Duplicate a network address. */
177 AG_NetAddr *
AG_NetAddrDup(const AG_NetAddr * na)178 AG_NetAddrDup(const AG_NetAddr *na)
179 {
180 	AG_NetAddr *naDup;
181 
182 	if ((naDup = AG_NetAddrNew()) == NULL) {
183 		return (NULL);
184 	}
185 	naDup->family = na->family;
186 	naDup->port = na->port;
187 	switch (na->family) {
188 	case AG_NET_LOCAL:
189 		if (na->na_local.path != NULL) {
190 			naDup->na_local.path = TryStrdup(na->na_local.path);
191 			if (naDup->na_local.path == NULL)
192 				goto fail;
193 		} else {
194 			naDup->na_local.path = NULL;
195 		}
196 		break;
197 	case AG_NET_INET4:
198 		naDup->na_inet4.addr = na->na_inet4.addr;
199 		break;
200 	case AG_NET_INET6:
201 		memcpy(naDup->na_inet6.addr, na->na_inet6.addr, sizeof(naDup->na_inet6.addr));
202 		break;
203 	}
204 	if (na->sNum != NULL) { naDup->sNum = TryStrdup(na->sNum); }
205 	if (na->sName != NULL) { naDup->sName = TryStrdup(na->sName); }
206 	return (naDup);
207 fail:
208 	free(naDup);
209 	return (NULL);
210 }
211 
212 /* Compare two network addresses. */
213 int
AG_NetAddrCompare(const AG_NetAddr * a,const AG_NetAddr * b)214 AG_NetAddrCompare(const AG_NetAddr *a, const AG_NetAddr *b)
215 {
216 	int diff;
217 
218 	if (a->family != b->family) {
219 		return (b->family - a->family);
220 	}
221 	if (a->port != b->port) {
222 		return (b->port - a->port);
223 	}
224 	switch (a->family) {
225 	case AG_NET_LOCAL:
226 		return strcmp(b->na_local.path, a->na_local.path);
227 	case AG_NET_INET4:
228 		diff = (b->na_inet4.addr - a->na_inet4.addr);
229 		if (diff != 0) { return (diff); }
230 	case AG_NET_INET6:
231 		diff = (b->na_inet6.addr - a->na_inet6.addr);
232 		if (diff != 0) { return (diff); }
233 	}
234 	return (0);
235 }
236 
237 /* Test if the given address represents "any" address. */
238 int
AG_NetAddrIsAny(const AG_NetAddr * na)239 AG_NetAddrIsAny(const AG_NetAddr *na)
240 {
241 	int i;
242 
243 	switch (na->family) {
244 	case AG_NET_INET4:
245 		return (na->na_inet4.addr == 0x00000000);
246 	case AG_NET_INET6:
247 		for (i = 0; i < sizeof(na->na_inet6.addr); i++) {
248 			if (na->na_inet6.addr[i] != 0)
249 				return (0);
250 		}
251 		return (1);
252 	default:
253 		return (0);
254 	}
255 }
256 
257 /*
258  * Return a numerical representation of the given network address.
259  * The string is allocated and freed internally with the AG_NetAddr.
260  */
261 const char *
AG_NetAddrNumerical(AG_NetAddr * na)262 AG_NetAddrNumerical(AG_NetAddr *na)
263 {
264 	return agNetOps->getAddrNumerical(na);
265 }
266 
267 /* Resolve the specified hostname and port name/number. */
268 AG_NetAddrList *
AG_NetResolve(const char * host,const char * port,Uint flags)269 AG_NetResolve(const char *host, const char *port, Uint flags)
270 {
271 	AG_NetAddrList *nal;
272 
273 	if ((nal = AG_NetAddrListNew()) == NULL) {
274 		return (NULL);
275 	}
276 	if (agNetOps->resolve(nal, host, port, flags) == -1) {
277 		goto fail;
278 	}
279 	return (nal);
280 fail:
281 	AG_NetAddrListFree(nal);
282 	return (NULL);
283 }
284 
285 /* Return the list of addresses associated with local network interfaces. */
286 AG_NetAddrList *
AG_NetGetIfConfig(void)287 AG_NetGetIfConfig(void)
288 {
289 	AG_NetAddrList *nal;
290 
291 	if ((nal = AG_NetAddrListNew()) == NULL) {
292 		return (NULL);
293 	}
294 	if (agNetOps->getIfConfig(nal) == -1) {
295 		goto fail;
296 	}
297 	return (nal);
298 fail:
299 	AG_NetAddrListFree(nal);
300 	return (NULL);
301 }
302 
303 /* Establish a connection to one of the network addresses specified. */
304 int
AG_NetConnect(AG_NetSocket * ns,const AG_NetAddrList * nal)305 AG_NetConnect(AG_NetSocket *ns, const AG_NetAddrList *nal)
306 {
307 	AG_NetAddr *na;
308 
309 	AG_MutexLock(&ns->lock);
310 
311 	if (ns->flags & AG_NET_SOCKET_BOUND) {
312 		AG_SetError(_("Socket is already bound"));
313 		goto fail;
314 	}
315 	if (ns->flags & AG_NET_SOCKET_CONNECTED) {
316 		AG_SetError(_("Socket is already connected"));
317 		goto fail;
318 	}
319 	TAILQ_FOREACH(na, nal, addrs) {
320 		if (agNetOps->connect(ns, na) == 0)
321 			break;
322 	}
323 	if (na == NULL) {
324 		AG_SetError(_("Connection failed"));
325 		goto fail;
326 	}
327 	ns->flags |= AG_NET_SOCKET_CONNECTED;
328 	ns->addrRemote = AG_NetAddrDup(na);
329 
330 	AG_MutexUnlock(&ns->lock);
331 	return (0);
332 fail:
333 	AG_MutexUnlock(&ns->lock);
334 	return (-1);
335 }
336 
337 /*
338  * Assign a local address to a socket. If the address happens to be
339  * of AG_NET_LOCAL family, a Unix socket is created in the filesystem.
340  */
341 int
AG_NetBind(AG_NetSocket * ns,const AG_NetAddr * na)342 AG_NetBind(AG_NetSocket *ns, const AG_NetAddr *na)
343 {
344 	AG_MutexLock(&ns->lock);
345 
346 	if (ns->flags & AG_NET_SOCKET_CONNECTED) {
347 		AG_SetError(_("Socket is already connected"));
348 		goto fail;
349 	}
350 	if (ns->flags & AG_NET_SOCKET_BOUND) {
351 		AG_SetError(_("Socket is already bound"));
352 		goto fail;
353 	}
354 	if (agNetOps->bind(ns, na) != 0) {
355 		goto fail;
356 	}
357 	ns->flags |= AG_NET_SOCKET_BOUND;
358 	ns->addrLocal = AG_NetAddrDup(na);
359 
360 	AG_MutexUnlock(&ns->lock);
361 	return (0);
362 fail:
363 	AG_MutexUnlock(&ns->lock);
364 	return (-1);
365 }
366 
367 /* Retrieve a socket option. */
368 int
AG_NetGetOption(AG_NetSocket * ns,enum ag_net_socket_option opt,void * arg)369 AG_NetGetOption(AG_NetSocket *ns, enum ag_net_socket_option opt, void *arg)
370 {
371 	int rv;
372 
373 	AG_MutexLock(&ns->lock);
374 	rv = agNetOps->getOption(ns, opt, arg);
375 	AG_MutexUnlock(&ns->lock);
376 	return (rv);
377 }
378 
379 /* Retrieve a socket option (integer). */
380 int
AG_NetGetOptionInt(AG_NetSocket * ns,enum ag_net_socket_option opt,int * arg)381 AG_NetGetOptionInt(AG_NetSocket *ns, enum ag_net_socket_option opt, int *arg)
382 {
383 	int rv;
384 
385 	AG_MutexLock(&ns->lock);
386 	rv = agNetOps->getOption(ns, opt, arg);
387 	AG_MutexUnlock(&ns->lock);
388 	return (rv);
389 }
390 
391 /* Set a socket option. */
392 int
AG_NetSetOption(AG_NetSocket * ns,enum ag_net_socket_option opt,const void * arg)393 AG_NetSetOption(AG_NetSocket *ns, enum ag_net_socket_option opt, const void *arg)
394 {
395 	int rv;
396 
397 	AG_MutexLock(&ns->lock);
398 	rv = agNetOps->setOption(ns, opt, arg);
399 	AG_MutexUnlock(&ns->lock);
400 	return (rv);
401 }
402 
403 /* Set a socket option (integer). */
404 int
AG_NetSetOptionInt(AG_NetSocket * ns,enum ag_net_socket_option opt,int val)405 AG_NetSetOptionInt(AG_NetSocket *ns, enum ag_net_socket_option opt, int val)
406 {
407 	int rv;
408 
409 	AG_MutexLock(&ns->lock);
410 	rv = agNetOps->setOption(ns, opt, &val);
411 	AG_MutexUnlock(&ns->lock);
412 	return (rv);
413 }
414 
415 /* Poll a set of sockets for read/write/exception events. */
416 int
AG_NetPoll(AG_NetSocketSet * nsInput,AG_NetSocketSet * nsRead,AG_NetSocketSet * nsWrite,AG_NetSocketSet * nsExcept,Uint32 timeout)417 AG_NetPoll(AG_NetSocketSet *nsInput, AG_NetSocketSet *nsRead,
418     AG_NetSocketSet *nsWrite, AG_NetSocketSet *nsExcept, Uint32 timeout)
419 {
420 	return agNetOps->poll(nsInput, nsRead, nsWrite, nsExcept, timeout);
421 }
422 
423 /* Accept a connection on a bound socket. */
424 AG_NetSocket *
AG_NetAccept(AG_NetSocket * ns)425 AG_NetAccept(AG_NetSocket *ns)
426 {
427 	AG_NetSocket *nsNew;
428 
429 	AG_MutexLock(&ns->lock);
430 	nsNew = agNetOps->accept(ns);
431 	AG_MutexUnlock(&ns->lock);
432 	return (nsNew);
433 }
434 
435 /* Read data from a socket. */
436 int
AG_NetRead(AG_NetSocket * ns,void * p,size_t size,size_t * nRead)437 AG_NetRead(AG_NetSocket *ns, void *p, size_t size, size_t *nRead)
438 {
439 	int rv;
440 
441 	AG_MutexLock(&ns->lock);
442 	rv = agNetOps->read(ns, p, size, nRead);
443 	AG_MutexUnlock(&ns->lock);
444 	return (rv);
445 }
446 
447 /* Write data to a socket. */
448 int
AG_NetWrite(AG_NetSocket * ns,const void * p,size_t size,size_t * nWrote)449 AG_NetWrite(AG_NetSocket *ns, const void *p, size_t size, size_t *nWrote)
450 {
451 	int rv;
452 
453 	AG_MutexLock(&ns->lock);
454 	rv = agNetOps->write(ns, p, size, nWrote);
455 	AG_MutexUnlock(&ns->lock);
456 	return (rv);
457 }
458 
459 /* Close a connection on a socket. */
460 void
AG_NetClose(AG_NetSocket * ns)461 AG_NetClose(AG_NetSocket *ns)
462 {
463 	AG_MutexLock(&ns->lock);
464 
465 	if ((ns->flags & AG_NET_SOCKET_CONNECTED) == 0) {
466 		goto out;
467 	}
468 	agNetOps->close(ns);
469 
470 	if (ns->addrLocal != NULL) {
471 		AG_NetAddrFree(ns->addrLocal);
472 		ns->addrLocal = NULL;
473 	}
474 	if (ns->addrRemote != NULL) {
475 		AG_NetAddrFree(ns->addrRemote);
476 		ns->addrRemote = NULL;
477 	}
478 	ns->flags &= ~(AG_NET_SOCKET_CONNECTED);
479 out:
480 	AG_MutexUnlock(&ns->lock);
481 }
482 
483 int
AG_InitNetworkSubsystem(const AG_NetOps * ops)484 AG_InitNetworkSubsystem(const AG_NetOps *ops)
485 {
486 	if (agNetOps == ops) {
487 		return (0);
488 	}
489 	if (agNetOps != NULL && agNetOps->destroy != NULL) {
490 		AG_DestroyNetworkSubsystem();
491 	}
492 	agNetOps = ops;
493 	return (ops->init != NULL) ? ops->init() : 0;
494 }
495 
496 void
AG_DestroyNetworkSubsystem(void)497 AG_DestroyNetworkSubsystem(void)
498 {
499 	if (agNetOps != NULL && agNetOps->destroy != NULL) {
500 		agNetOps->destroy();
501 	}
502 	agNetOps = NULL;
503 }
504