1 /*
2  * Copyright (c) 2008
3  *      Matt Harris.  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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      "This product includes software developed by Matt Harris."
16  * 4. Neither the name of the Mr. Harris nor the names of his contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  * 5. Any modifications and/or variations in the end-product which you are
20  *    distributing from the original source code are clearly noted in
21  *    the standard end-user documentation distributed with any package
22  *    containing this software in either source or binary form, as well
23  *    as on any internet sites or media on which this software is included.
24  *
25  * THIS SOFTWARE IS PROVIDED BY Mr. Harris AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL Mr. Harris OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  */
38 
39 #include <msocket-internal.h>
40 #include <fcntl.h>
41 #include <sys/ioctl.h>
42 #include <sys/uio.h>
43 
44 static MSocket *_lms_socket_list[LMS_HIGHSOCK];
45 static MSocket *_lms_socket_corpses[LMS_HIGHSOCK];
46 
47 
48 /*
49  * Initialize the list of MSocket objects in _lms_socket_list
50  *
51  */
lms_socket_init()52 int *lms_socket_init()
53 {
54 	register unsigned int i;
55 
56 	for (i = 0; i < LMS_HIGHSOCK; ++i)
57 	{
58 		_lms_socket_list[i] = (MSocket *)NULL;
59 		_lms_socket_corpses[i] = (MSocket *)NULL;
60 	}
61 
62 	return(0);
63 }
64 
65 /*
66  * Add an fd to the local socket list
67  *
68  * fd = the fd to add it as an indexer
69  * m = the MSocket object to add to the list
70  *
71  */
lms_socket_insertfd(MSocket * m)72 void lms_socket_insertfd(MSocket *m)
73 {
74 	if (!m)
75 	{
76 		return;
77 	}
78 	if ((m->fd < 0) || (m->fd >= LMS_HIGHSOCK))
79 	{
80 		return;
81 	}
82 
83 	_lms_socket_list[m->fd] = m;
84 	return;
85 }
86 
87 /*
88  * Find the MSocket object corresponding to a given file descriptor
89  *
90  * fd = the file descriptor you wish to find the corresponding MSocket object for
91  *
92  */
lms_socket_findbyfd(int fd)93 inline MSocket *lms_socket_findbyfd(int fd)
94 {
95 	if (_lms_socket_list[fd])
96 	{
97 		return(_lms_socket_list[fd]);
98 	}
99 	else
100 	{
101 		return((MSocket *)NULL);
102 	}
103 }
104 
105 /*
106  * Create and allocate memory for a new MSocket object
107  *
108  * type = the type of the new socket to allocate
109  *
110  */
lms_socket_create(int type)111 MSocket *lms_socket_create(int type)
112 {
113 	MSocket *ptr;
114 
115 	ptr = (MSocket *)NULL;
116 #ifdef LMS_HARDCORE_ALLOC
117 	while (!ptr)
118 	{
119 		ptr = (MSocket *)malloc(sizeof(MSocket));
120 	}
121 #else
122 	ptr = (MSocket *)malloc(sizeof(MSocket));
123 	if (!ptr)
124 	{
125 		return((MSocket *)NULL);
126 	}
127 #endif
128 	memset(ptr, 0, sizeof(MSocket));
129 
130 	ptr->type = type;
131 	ptr->fd = -1;
132 	ptr->flags = 0;
133 	ptr->opts = 0;
134 
135 	ptr->sendQ_sz = 0;
136 	ptr->sendQ_len = 0;
137 	ptr->sendQ = (unsigned char *)NULL;
138 	ptr->recvQ_sz = 0;
139 	ptr->recvQ_len = 0;
140 	ptr->recvQ = (unsigned char *)NULL;
141 
142 	if (type == LMSTYPE_LOCALLISTEN)
143 	{
144 		ptr->localhost = (char *)malloc(MAXPATHLEN);
145 		if (!ptr->localhost)
146 		{
147 			free(ptr);
148 			return((MSocket *)NULL);
149 		}
150 		memset(ptr->localhost, 0, MAXPATHLEN);
151 	}
152 	else if ((type == LMSTYPE_LISTEN4) || (type == LMSTYPE_STREAM4) || (type == LMSTYPE_DGRAM4))
153 	{
154 		/* Space for an IPv4 address */
155 		ptr->localhost = (char *)malloc(LMS_LEN_V4ADDR);
156 		if (!ptr->localhost)
157 		{
158 			free(ptr);
159 			return((MSocket *)NULL);
160 		}
161 		memset(ptr->localhost, 0, LMS_LEN_V4ADDR);
162 	}
163 	else if ((type == LMSTYPE_LISTEN6) || (type == LMSTYPE_STREAM6) || (type == LMSTYPE_DGRAM6))
164 	{
165 		/* Space for an IPv6 address */
166 		ptr->localhost = (char *)malloc(LMS_LEN_V6ADDR);
167 		if (!ptr->localhost)
168 		{
169 			free(ptr);
170 			return((MSocket *)NULL);
171 		}
172 		memset(ptr->localhost, 0, LMS_LEN_V6ADDR);
173 	}
174 	else
175 	{
176 		ptr->localhost = (char *)NULL;
177 	}
178 	ptr->localport = 0;
179 
180 	if ((type == LMSTYPE_STREAM4) || (type == LMSTYPE_DGRAM4))
181 	{
182 		/* Space for an IPv4 address */
183 		ptr->remotehost = (char *)malloc(LMS_LEN_V4ADDR);
184 		if (!ptr->remotehost)
185 		{
186 			if (ptr->localhost)
187 			{
188 				free(ptr->localhost);
189 			}
190 			free(ptr);
191 			return((MSocket *)NULL);
192 		}
193 		memset(ptr->remotehost, 0, LMS_LEN_V4ADDR);
194 	}
195 	else if ((type == LMSTYPE_STREAM6) || (type == LMSTYPE_DGRAM6))
196 	{
197 		/* Space for an IPv6 address */
198 		ptr->remotehost = (char *)malloc(LMS_LEN_V6ADDR);
199 		if (!ptr->remotehost)
200 		{
201 			if (ptr->localhost)
202 			{
203 				free(ptr->localhost);
204 			}
205 			free(ptr);
206 			return((MSocket *)NULL);
207 		}
208 		memset(ptr->remotehost, 0, LMS_LEN_V6ADDR);
209 	}
210 	else
211 	{
212 		ptr->remotehost = (char *)NULL;
213 	}
214 	ptr->remoteport = 0;
215 
216 	ptr->last_send = time(NULL);
217 	ptr->bytes_s = 0;
218 	ptr->last_recv = time(NULL);
219 	ptr->bytes_r = 0;
220 
221 	ptr->remotedns = (char *)NULL;
222 
223 	ptr->appdata = (void *)NULL;
224 
225 	/*
226 	 * Callbacks to the application abstraction layer -
227 	 * These end up called when the back-end stuff has been taken care of and the application layer can act
228 	 */
229 	ptr->func_r = lms_socket_read;
230 	ptr->func_w = lms_socket_flushq;
231 	ptr->func_e = lms_conn_default_error;
232 	ptr->func_p = lms_conn_default_read;
233 	ptr->func_a = lms_conn_default_accept;
234 
235 	/*
236 	 * Stuff for the reverse DNS resolver.
237 	 */
238 	/* ptr->addr is the remote address, and is only set once we start doing a reverse DNS lookup */
239 	ptr->addr = (struct in_addr *)malloc(sizeof(struct in_addr));
240 	if (!ptr->addr)
241 	{
242 		free(ptr);
243 		return((MSocket *)NULL);
244 	}
245 	memset(ptr->addr, 0, sizeof(struct in_addr));
246 	/* This is not usually set; it is used between the first and second phase of reverse DNS lookup prior to the verification that the PTR is valid */
247 	ptr->possible_revdns = (char *)NULL;
248 	/* This specifies retries for the reverse DNS resolver */
249 	ptr->retries = 0;
250 
251 	ptr->conn_start = 0;
252 	ptr->conn_to = LMS_CONNTIMEOUT;
253 
254 	return(ptr);
255 }
256 
257 /*
258  * Close a Socket cleanly - dump sendQ before destroying it
259  *
260  * ptr = the socket to close
261  *
262  */
lms_socket_close(MSocket * ptr)263 int lms_socket_close(MSocket *ptr)
264 {
265 	if (!ptr)
266 	{
267 		errno = EINVAL;
268 		return(-1);
269 	}
270 	else if (ptr->flags & LMSFLG_WAITDESTROY)
271 	{
272 		errno = EINVAL;
273 		return(-1);
274 	}
275 
276 	if (ptr->flags & LMSFLG_MUXACTIVE)
277 	{
278 		lms_mux_remfd(ptr->fd);
279 	}
280 
281 	if (ptr->sendQ_len > 0)
282 	{
283 		ptr->func_w(ptr);
284 	}
285 
286 	if (ptr->flags & LMSFLG_SSL)
287 	{
288 		lms_ssl_closesock(ptr);
289 	}
290 
291 	lms_socket_destroy(ptr);
292 
293 	return(0);
294 }
295 
296 /*
297  * Destroy an existing MSocket object and free the memory
298  *
299  * ptr = an MSocket created by lms_socket_create()
300  *
301  */
lms_socket_destroy(MSocket * ptr)302 int lms_socket_destroy(MSocket *ptr)
303 {
304 	if (!ptr)
305 	{
306 		errno = EINVAL;
307 		return(-1);
308 	}
309 
310 	if (ptr->flags & LMSFLG_SSL)
311 	{
312 		lms_ssl_stopsock(ptr);
313 	}
314 
315 	if (ptr->flags & LMSFLG_MUXACTIVE)
316 	{
317 		lms_mux_remfd(ptr->fd);
318 	}
319 
320 	if (ptr->recvQ_sz > 0)
321 	{
322 		if (ptr->recvQ)
323 		{
324 			free(ptr->recvQ);
325 			ptr->recvQ = (unsigned char *)NULL;
326 			ptr->recvQ_sz = 0;
327 		}
328 	}
329 	if (ptr->sendQ_sz > 0)
330 	{
331 		if (ptr->sendQ)
332 		{
333 			free(ptr->sendQ);
334 			ptr->sendQ = (unsigned char *)NULL;
335 			ptr->sendQ_sz = 0;
336 		}
337 	}
338 
339 	/*
340 	 * One thing worth noting is that appdata needs to be taken care of elsewhere before
341 	 * calling lms_socket_destroy() - some things, like interface/local utilize appdata
342 	 * as the only place where a pointer is stored, so a failure to deal with appdata could
343 	 * result in memory leaks in such places.
344 	 */
345 
346 	if (!(ptr->flags & LMSFLG_WAITDESTROY))
347 	{
348 		_lms_socket_list[ptr->fd] = (MSocket *)NULL;
349 
350 		if (ptr->type != LMSTYPE_LOCALLISTEN)
351 		{
352 			/*
353 			 * interface/local.c has its own method of dealing with closing the socket
354 			 * which also includes calling unlink() on the file and such
355 			 */
356 			if (ptr->flags & LMSFLG_CONNECTED)
357 			{
358 				/* stream */
359 				shutdown(ptr->fd, SHUT_RDWR);
360 				ptr->flags &= ~LMSFLG_CONNECTED;
361 			}
362 			else if (ptr->flags & LMSFLG_READY)
363 			{
364 				/* dgram */
365 				shutdown(ptr->fd, SHUT_RDWR);
366 				ptr->flags &= ~LMSFLG_READY;
367 			}
368 			close(ptr->fd);
369 		}
370 	}
371 	else
372 	{
373 		if ((ptr->flags & LMSFLG_WAITDNS) || (ptr->flags & LMSFLG_WAITIDENT))
374 		{
375 			_lms_socket_corpses[ptr->fd] = ptr;
376 			return(0);
377 		}
378 		else
379 		{
380 			/*
381 			 * Do you see it?
382 			 * There's a possible race condition if a socket becomes a 'corpse' before the last corpse that had that same fd
383 			 * number has its DNS query return... Hmm.  The likelihood is small, however, and the impact is a small memory
384 			 * leak, so I'll worry about it later.
385 			 */
386 			_lms_socket_corpses[ptr->fd] = (MSocket *)NULL;
387 		}
388 	}
389 
390 	if ((ptr->flags & LMSFLG_WAITDNS) || (ptr->flags & LMSFLG_WAITIDENT))
391 	{
392 		/* We can't safely destroy it yet. */
393 		ptr->flags |= LMSFLG_WAITDESTROY;
394 		ptr->flags &= ~LMSFLG_CONNECTED;
395 		ptr->flags &= ~LMSFLG_READY;
396 		_lms_socket_corpses[ptr->fd] = ptr;
397 		return(0);
398 	}
399 
400 	if (ptr->remotedns)
401 	{
402 		free(ptr->remotedns);
403 		ptr->remotedns = (char *)NULL;
404 	}
405 	if (ptr->remotehost)
406 	{
407 		free(ptr->remotehost);
408 		ptr->remotehost = (char *)NULL;
409 	}
410 	if (ptr->localhost)
411 	{
412 		free(ptr->localhost);
413 		ptr->localhost = (char *)NULL;
414 	}
415 
416 	if (ptr->addr)
417 	{
418 		free(ptr->addr);
419 		ptr->addr = (struct in_addr *)NULL;
420 	}
421 	if (ptr->possible_revdns)
422 	{
423 		free(ptr->possible_revdns);
424 		ptr->possible_revdns = (char *)NULL;
425 	}
426 
427 	free(ptr);
428 
429 	return(0);
430 }
431 
432 /*
433  * Dump all connections of a specific type
434  *
435  * type = the type to dump all of
436  * killad = boolean var as to whether the appdata field should be checked and free()'d if it exists
437  *
438  */
lms_socket_destroytype(unsigned short type,short killad)439 unsigned int lms_socket_destroytype(unsigned short type, short killad)
440 {
441 	unsigned int num;
442 	register unsigned int i;
443 
444 	errno = 0;
445 
446 	if ((killad != 0) && (killad != 1))
447 	{
448 		errno = EINVAL;
449 		return(0);
450 	}
451 	if (type == LMSTYPE_ERROR)
452 	{
453 		return(0);
454 	}
455 	else if (type == LMSTYPE_LOCALLISTEN)
456 	{
457 		return(0);
458 	}
459 
460 	num = 0;
461 
462 	for (i = 0; i < LMS_HIGHSOCK; ++i)
463 	{
464 		if (!_lms_socket_list[i])
465 		{
466 			continue;
467 		}
468 
469 		if (_lms_socket_list[i]->type == type)
470 		{
471 			if (killad && _lms_socket_list[i]->appdata)
472 			{
473 				free(_lms_socket_list[i]->appdata);
474 				_lms_socket_list[i]->appdata = (void *)NULL;
475 			}
476 			if (_lms_socket_list[i]->flags & LMSFLG_MUXACTIVE)
477 			{
478 				lms_mux_remfd(_lms_socket_list[i]->fd);
479 			}
480 			lms_socket_destroy(_lms_socket_list[i]);
481 			num++;
482 		}
483 	}
484 
485 	return(num);
486 }
487 
488 /*
489  * Dump dumpable corpses
490  * Dump connections with nothing going on to prevent resource-starvation attacks as best as possible
491  * Flush sendQs
492  *
493  */
lms_socket_housekeeping()494 unsigned int lms_socket_housekeeping()
495 {
496 	unsigned int num;
497 	register unsigned int i;
498 	int ka;
499 	time_t current;
500 
501 	current = time(NULL);
502 	num = 0;
503 
504 	for (i = 0; i < LMS_HIGHSOCK; ++i)
505 	{
506 		if (_lms_socket_corpses[i])
507 		{
508 			if ((_lms_socket_corpses[i]->flags & LMSFLG_WAITDESTROY) && !(_lms_socket_list[i]->flags & LMSFLG_WAITDNS) && !(_lms_socket_list[i]->flags & LMSFLG_WAITIDENT))
509 			{
510 				/* Query finished, we can now safely destroy it without crashing. */
511 				lms_socket_destroy(_lms_socket_corpses[i]);
512 				continue;
513 			}
514 		}
515 
516 		if (!_lms_socket_list[i])
517 		{
518 			continue;
519 		}
520 
521 		if ((_lms_socket_list[i]->flags & LMSFLG_WAITCONN) && (_lms_socket_list[i]->conn_start < (current - _lms_socket_list[i]->conn_to)))
522 		{
523 			if (_lms_socket_list[i]->func_e)
524 			{
525 				_lms_socket_list[i]->func_e(_lms_socket_list[i]);
526 			}
527 			else
528 			{
529 				if (_lms_socket_list[i]->flags & LMSFLG_MUXACTIVE)
530 				{
531 					lms_mux_remfd(_lms_socket_list[i]->fd);
532 				}
533 				lms_socket_destroy(_lms_socket_list[i]);
534 			}
535 			num++;
536 			continue;
537 		}
538 
539 		if ((_lms_socket_list[i]->type == LMSTYPE_LISTEN4) || (_lms_socket_list[i]->type == LMSTYPE_LISTEN6) || (_lms_socket_list[i]->type == LMSTYPE_LOCALLISTEN))
540 		{
541 			continue;
542 		}
543 		else if (_lms_socket_list[i]->opts & LMSOPTION_ALLOWIDLE)
544 		{
545 			continue;
546 		}
547 		else if (_lms_socket_list[i]->type == LMSTYPE_LOCALCLIENT)
548 		{
549 			/* Give local clients at least an hour. */
550 #if (LMS_MAXKEEPALIVE < 3600)
551 			ka = 3600;
552 #else
553 			ka = LMS_MAXKEEPALIVE;
554 #endif
555 		}
556 		else
557 		{
558 			ka = LMS_MAXKEEPALIVE;
559 		}
560 
561 		if ((_lms_socket_list[i]->last_recv <= (current - ka)) && (_lms_socket_list[i]->last_send <= (current - ka)))
562 		{
563 			if (_lms_socket_list[i]->flags & LMSFLG_MUXACTIVE)
564 			{
565 				lms_mux_remfd(_lms_socket_list[i]->fd);
566 			}
567 			lms_socket_destroy(_lms_socket_list[i]);
568 			num++;
569 			continue;
570 		}
571 
572 		if (_lms_socket_list[i]->sendQ_len > 0)
573 		{
574 			_lms_socket_list[i]->func_w(_lms_socket_list[i]);
575 		}
576 	}
577 
578 	return(num);
579 }
580 
581 /*
582  * Initiate listening on an MSocket object
583  *
584  * s = a new MSocket created by lms_socket_create()
585  *
586  */
lms_socket_ilisten(MSocket * s)587 int lms_socket_ilisten(MSocket *s)
588 {
589         int fd_opts;
590         struct sockaddr_in s_local_host;
591 
592 	if (!s)
593 	{
594 		errno = EINVAL;
595 		return(-1);
596 	}
597 
598 	if ((s->type != LMSTYPE_LISTEN4) && (s->type != LMSTYPE_LISTEN6))
599 	{
600 		errno = EINVAL;
601 		return(-1);
602 	}
603 	if (s->localport <= 0)
604 	{
605 		errno = EADDRNOTAVAIL;
606 		return(-1);
607 	}
608 	if ((s->flags & LMSFLG_CONNECTED) || (s->flags & LMSFLG_LISTEN))
609 	{
610 		errno = EISCONN;
611 		return(-1);
612 	}
613 
614 	s->fd = socket(PF_INET, SOCK_STREAM, 0);
615 	if (s->fd < 0)
616 	{
617 		return(-1);
618 	}
619 
620 	memset(&s_local_host, 0, sizeof(s_local_host));
621 	s_local_host.sin_family = AF_INET;
622 	s_local_host.sin_port = htons(s->localport);
623 	if (!s->localhost || (*s->localhost == '\0'))
624 	{
625 		s_local_host.sin_addr.s_addr = INADDR_ANY;
626 	}
627 	else if (inet_addr(s->localhost) == INADDR_NONE)
628 	{
629 		s_local_host.sin_addr.s_addr = INADDR_ANY;
630 	}
631 	else
632 	{
633 		s_local_host.sin_addr.s_addr = inet_addr(s->localhost);
634 	}
635 
636 	if (bind(s->fd, (struct sockaddr *)&s_local_host, sizeof(s_local_host)) != 0)
637 	{
638 		close(s->fd);
639 		return(-1);
640 	}
641 
642 	fd_opts = fcntl(s->fd, F_GETFL, 0);
643 	fcntl(s->fd, F_SETFL, fd_opts|O_NONBLOCK);
644 	if (listen(s->fd, LMS_BACKLOG) != 0)
645 	{
646 		close(s->fd);
647 		return(-1);
648 	}
649 
650 	if (s->opts & LMSOPTION_SSL)
651 	{
652 		s->flags |= LMSFLG_SSL;
653 	}
654 
655 	s->flags |= LMSFLG_LISTEN;
656 	_lms_socket_list[s->fd] = s;
657 
658 	return(0);
659 }
660 
661 /*
662  * Accept a new connection on a listener
663  *
664  * s = the listener on which to accept the new connection
665  * new = a new MSocket created by lms_socket_create() which will be propagated by this function
666  *
667  */
lms_socket_iaccept(MSocket * s,MSocket * new)668 int lms_socket_iaccept(MSocket *s, MSocket *new)
669 {
670 	int fd_opts;
671 	unsigned int srh_sz;
672 	struct sockaddr_in s_remote_host;
673 
674 	if (!s || !new)
675 	{
676 		errno = EINVAL;
677 		return(-1);
678 	}
679 	if (!(s->flags & LMSFLG_LISTEN))
680 	{
681 		errno = EOPNOTSUPP;
682 		return(-1);
683 	}
684 	if ((new->type != LMSTYPE_STREAM4) && (new->type != LMSTYPE_STREAM6))
685 	{
686 		errno = EINVAL;
687 		return(-1);
688 	}
689 
690 	srh_sz = sizeof(struct sockaddr_in);
691 
692 	while ((new->fd = accept(s->fd, (struct sockaddr *)&s_remote_host, &srh_sz)) < 0)
693 	{
694 		if ((errno == EAGAIN) || (errno = EINTR))
695 		{
696 			continue;
697 		}
698 		else
699 		{
700 			return(-1);
701 		}
702 	}
703 
704 	if (*s->localhost != '\0')
705 	{
706 		/* FIXME: V6 support needed here. */
707 		if ((new->type == LMSTYPE_STREAM4) || (new->type == LMSTYPE_DGRAM4))
708 		{
709 			memcpy(new->localhost, s->localhost, LMS_LEN_V4ADDR);
710 		}
711 		else if ((new->type == LMSTYPE_STREAM6) || (new->type == LMSTYPE_DGRAM6))
712 		{
713 			memcpy(new->localhost, s->localhost, LMS_LEN_V6ADDR);
714 		}
715 	}
716 	new->localport = s->localport;
717 	if ((new->type == LMSTYPE_STREAM4) || (new->type == LMSTYPE_DGRAM4))
718 	{
719 		snprintf(new->remotehost, LMS_LEN_V4ADDR, "%s", inet_ntoa(s_remote_host.sin_addr));
720 	}
721 	else if ((new->type == LMSTYPE_STREAM6) || (new->type == LMSTYPE_DGRAM6))
722 	{
723 		snprintf(new->remotehost, LMS_LEN_V6ADDR, "%s", inet_ntoa(s_remote_host.sin_addr));
724 	}
725 	new->remoteport = s_remote_host.sin_port;
726 
727 	new->addr->s_addr = s_remote_host.sin_addr.s_addr;
728 
729 	if (!(new->opts & LMSOPTION_BLOCK))
730 	{
731 		fd_opts = fcntl(new->fd, F_GETFL, 0);
732 		fcntl(new->fd, F_SETFL, fd_opts|O_NONBLOCK);
733 	}
734 
735 	new->flags |= LMSFLG_CONNECTED|LMSFLG_INBOUND;
736 
737 	new->func_r = lms_socket_read;
738 	new->func_w = lms_socket_flushq;
739 
740 	if (s->flags & LMSFLG_SSL)
741 	{
742 		new->opts |= LMSOPTION_SSL;
743 		/* lms_ssl_startsock() will update func_r and func_w appropriately */
744 		lms_ssl_startsock(new);
745 	}
746 
747 	_lms_socket_list[new->fd] = new;
748 
749 	return(0);
750 }
751 
752 /*
753  * Accept a new connection on a UNIX domain socket listener
754  *
755  * s = the listener on which to accept the new connection
756  * new = a new MSocket created by lms_socket_create() which will be propagated by this function
757  *
758  */
lms_socket_uaccept(MSocket * s,MSocket * new)759 int lms_socket_uaccept(MSocket *s, MSocket *new)
760 {
761 	int fd_opts;
762 	unsigned int srh_sz;
763 	struct sockaddr_un s_remote_host;
764 
765 	if (!s || !new)
766 	{
767 		errno = EINVAL;
768 		return(-1);
769 	}
770 	if (!(s->flags & LMSFLG_LISTEN))
771 	{
772 		errno = EOPNOTSUPP;
773 		return(-1);
774 	}
775 	if (new->type != LMSTYPE_LOCALCLIENT)
776 	{
777 		errno = EINVAL;
778 		return(-1);
779 	}
780 
781 	srh_sz = sizeof(struct sockaddr_un);
782 
783 	while ((new->fd = accept(s->fd, (struct sockaddr *)&s_remote_host, &srh_sz)) < 0)
784 	{
785 		if (errno == EAGAIN)
786 		{
787 			continue;
788 		}
789 		else
790 		{
791 			return(-1);
792 		}
793 	}
794 
795 	fd_opts = fcntl(new->fd, F_GETFL, 0);
796 	fcntl(new->fd, F_SETFL, fd_opts|O_NONBLOCK);
797 
798 	new->flags |= LMSFLG_CONNECTED|LMSFLG_INBOUND;
799 	_lms_socket_list[new->fd] = new;
800 
801 	return(0);
802 }
803 
804 /*
805  * Initiate an outbound connection on an MSocket object
806  *
807  * s = a new MSocket created by lms_socket_create()
808  *
809  */
lms_socket_iconn(MSocket * s)810 int lms_socket_iconn(MSocket *s)
811 {
812 	int fd_opts;
813 	struct sockaddr_in s_local_host;
814 	static struct sockaddr_in s_remote_host;
815 
816 	if (!s)
817 	{
818 		errno = EINVAL;
819 		return(-1);
820 	}
821 	if (!s->remotehost || (*s->remotehost == '\0') || (s->remoteport <= 0))
822 	{
823 		errno = EDESTADDRREQ;
824 		return(-1);
825 	}
826 	if ((s->type != LMSTYPE_STREAM4) && (s->type != LMSTYPE_STREAM6))
827 	{
828 		errno = EINVAL;
829 		return(-1);
830 	}
831 	if ((s->flags & LMSFLG_CONNECTED) || (s->flags & LMSFLG_LISTEN))
832 	{
833 		errno = EISCONN;
834 		return(-1);
835 	}
836 
837 	s->fd = socket(PF_INET, SOCK_STREAM, 0);
838 	if (s->fd < 0)
839 	{
840 		return(-1);
841 	}
842 
843 	memset(&s_local_host, 0, sizeof(s_local_host));
844 	s_local_host.sin_family = AF_INET;
845 	s_local_host.sin_port = htons(s->localport);
846 	if (!s->localhost || (s->localhost[0] == 0))
847 	{
848 		s_local_host.sin_addr.s_addr = INADDR_ANY;
849 	}
850 	else if (inet_addr(s->localhost) == INADDR_NONE)
851 	{
852 		s_local_host.sin_addr.s_addr = INADDR_ANY;
853 	}
854 	else
855 	{
856 		s_local_host.sin_addr.s_addr = inet_addr(s->localhost);
857 	}
858 
859 	if (bind(s->fd, (struct sockaddr *)&s_local_host, sizeof(struct sockaddr_in)) != 0)
860 	{
861 		close(s->fd);
862 		return(-1);
863 	}
864 
865 	if (!(s->opts & LMSOPTION_CWAIT) && !(s->opts & LMSOPTION_BLOCK))
866 	{
867 		fd_opts = fcntl(s->fd, F_GETFL, 0);
868 		fcntl(s->fd, F_SETFL, fd_opts|O_NONBLOCK);
869 	}
870 
871 	memset(&s_remote_host, 0, sizeof(s_remote_host));
872 	s_remote_host.sin_family = AF_INET;
873 	s_remote_host.sin_addr.s_addr = inet_addr(s->remotehost);
874 	s_remote_host.sin_port = htons(s->remoteport);
875 	if (connect(s->fd, (struct sockaddr *)&s_remote_host, sizeof(struct sockaddr_in)) != 0)
876 	{
877 		if (errno == EISCONN)
878 		{
879 			/* This is a "wtf?" */
880 			return(-1);
881 		}
882 		else if (errno != EINPROGRESS)
883 		{
884 			close(s->fd);
885 			return(-1);
886 		}
887 
888 		s->flags |= LMSFLG_WAITCONN;
889 		s->conn_start = time(NULL);
890 	}
891 	else
892 	{
893 		s->flags |= LMSFLG_CONNECTED;
894 	}
895 
896 	s->addr->s_addr = inet_addr(s->remotehost);
897 
898 	if ((s->opts & LMSOPTION_CWAIT) && !(s->opts & LMSOPTION_BLOCK))
899 	{
900 		fd_opts = fcntl(s->fd, F_GETFL, 0);
901 		fcntl(s->fd, F_SETFL, fd_opts|O_NONBLOCK);
902 	}
903 
904 	s->flags |= LMSFLG_OUTBOUND;
905 
906 	s->func_r = lms_socket_read;
907 	s->func_w = lms_socket_flushq;
908 
909 	if (s->opts & LMSOPTION_SSL)
910 	{
911 		/* lms_ssl_startsock() will update func_r and func_w appropriately */
912 		lms_ssl_startsock(s);
913 	}
914 
915 	_lms_socket_list[s->fd] = s;
916 
917 	return(0);
918 }
919 
920 /*
921  * Initiate a connection-less datagram socket on an MSocket object
922  *
923  * s = a new MSocket created by lms_socket_create()
924  *
925  */
lms_socket_idgram(MSocket * s)926 int lms_socket_idgram(MSocket *s)
927 {
928 	int fd_opts;
929 	struct sockaddr_in s_local_host;
930 
931 	if (!s)
932 	{
933 		errno = EINVAL;
934 		return(-1);
935 	}
936 	if (!((s->type == LMSTYPE_DGRAM4) || (s->type == LMSTYPE_DGRAM6)))
937 	{
938 		errno = EINVAL;
939 		return(-1);
940 	}
941 	if ((s->flags & LMSFLG_CONNECTED) || (s->flags & LMSFLG_LISTEN))
942 	{
943 		errno = EISCONN;
944 		return(-1);
945 	}
946 
947 	s->fd = socket(PF_INET, SOCK_DGRAM, 0);
948 	if (s->fd < 0)
949 	{
950 		return(-1);
951 	}
952 
953 	memset(&s_local_host, 0, sizeof(s_local_host));
954 	s_local_host.sin_family = AF_INET;
955 	s_local_host.sin_port = htons(s->localport);
956 	if (!s->localhost || (s->localhost[0] == 0))
957 	{
958 		s_local_host.sin_addr.s_addr = INADDR_ANY;
959 	}
960 	else if (inet_addr(s->localhost) == INADDR_NONE)
961 	{
962 		s_local_host.sin_addr.s_addr = INADDR_ANY;
963 	}
964 	else
965 	{
966 		s_local_host.sin_addr.s_addr = inet_addr(s->localhost);
967 	}
968 
969 	if (bind(s->fd, (struct sockaddr *)&s_local_host, sizeof(struct sockaddr_in)) != 0)
970 	{
971 		close(s->fd);
972 		return(-1);
973 	}
974 
975 	fd_opts = fcntl(s->fd, F_GETFL, 0);
976 	fcntl(s->fd, F_SETFL, fd_opts|O_NONBLOCK);
977 
978 	_lms_socket_list[s->fd] = s;
979 
980 	/* If a remoteport and remotehost are given, call it an outbound socket, otherwise treat it as an inbound socket */
981 	if ((s->remoteport > 0) && s->remotehost && (s->remotehost[0] != 0))
982 	{
983 		s->flags |= LMSFLG_CONNECTED|LMSFLG_OUTBOUND;
984 	}
985 	else
986 	{
987 		s->flags |= LMSFLG_LISTEN|LMSFLG_INBOUND;
988 	}
989 	s->flags |= LMSFLG_READY;
990 
991 	return(0);
992 }
993 
994 /*
995  * Read from a connection
996  *
997  * m = the connection to read from
998  *
999  */
lms_socket_read(MSocket * m)1000 int lms_socket_read(MSocket *m)
1001 {
1002 	unsigned char *c;
1003 	int recvrv;
1004 	size_t bufsz;
1005 	unsigned char callpfunc;
1006 
1007 	if (!m)
1008 	{
1009 		errno = EINVAL;
1010 		return(-1);
1011 	}
1012 	if (!(m->flags & LMSFLG_CONNECTED))
1013 	{
1014 		errno = ENOTCONN;
1015 		return(-1);
1016 	}
1017 	if ((m->type != LMSTYPE_STREAM4) && (m->type != LMSTYPE_STREAM6))
1018 	{
1019 		errno = EINVAL;
1020 		return(-1);
1021 	}
1022 
1023 	callpfunc = 0;
1024 	bufsz = 1024;
1025 
1026 	c = (unsigned char *)malloc(bufsz);
1027 	if (!c)
1028 	{
1029 		return(-1);
1030 	}
1031 	memset(c, 0, bufsz);
1032 
1033 	if ((m->recvQ_sz > 0) && m->recvQ)
1034 	{
1035 		if (m->recvQ_sz < (m->recvQ_len + bufsz))
1036 		{
1037 #ifdef HAVE_REALLOCF
1038 			m->recvQ = (unsigned char *)reallocf(m->recvQ, (m->recvQ_sz + bufsz));
1039 #else
1040 			m->recvQ = (unsigned char *)realloc(m->recvQ, (m->recvQ_sz + bufsz));
1041 #endif /* HAVE_REALLOCF */
1042 			if (!m->recvQ)
1043 			{
1044 				free(c);
1045 				return(-1);
1046 			}
1047 			m->recvQ_sz += bufsz;
1048 		}
1049 	}
1050 	else
1051 	{
1052 		m->recvQ = (unsigned char *)malloc(bufsz);
1053 		if (!m->recvQ)
1054 		{
1055 			free(c);
1056 			return(-1);
1057 		}
1058 		m->recvQ_sz = bufsz;
1059 	}
1060 
1061 	while (1)
1062 	{
1063 #ifdef MSG_DONTWAIT
1064 # define _SERVER_SOCKET_RECVFLAGS		MSG_DONTWAIT
1065 #else
1066 # define _SERVER_SOCKET_RECVFLAGS		0
1067 #endif
1068 		recvrv = recv(m->fd, c, bufsz, _SERVER_SOCKET_RECVFLAGS);
1069 
1070 		if (recvrv < 0)
1071 		{
1072 			if ((errno == EAGAIN) || (errno == EINTR))
1073 			{
1074 				break;
1075 			}
1076 			else
1077 			{
1078 				m->func_e(m);
1079 				return(0);
1080 			}
1081 		}
1082 		else if (recvrv == 0)
1083 		{
1084 			m->func_e(m);
1085 			return(0);
1086 		}
1087 		else
1088 		{
1089 			lms_str_ocopy(c, m->recvQ, recvrv, m->recvQ_len);
1090 			m->recvQ_len += recvrv;
1091 			memset(c, 0, bufsz);
1092 			callpfunc = 1;
1093 			m->bytes_r += recvrv;
1094 		}
1095 
1096 		if (m->recvQ_sz < (m->recvQ_len + bufsz))
1097 		{
1098 #ifdef HAVE_REALLOCF
1099 			m->recvQ = (unsigned char *)reallocf(m->recvQ, (m->recvQ_sz + bufsz));
1100 #else
1101 			m->recvQ = (unsigned char *)realloc(m->recvQ, (m->recvQ_sz + bufsz));
1102 #endif /* HAVE_REALLOCF */
1103 			if (!m->recvQ)
1104 			{
1105 				free(c);
1106 				return(-1);
1107 			}
1108 			m->recvQ_sz += bufsz;
1109 		}
1110 	}
1111 
1112 	if (callpfunc)
1113 	{
1114 		m->func_p(m);
1115 	}
1116 	m->last_recv = time(NULL);
1117 
1118 	free(c);
1119 	return(0);
1120 }
1121 
1122 /*
1123  * Flush the sendQ of a socket
1124  *
1125  * m = the socket to flush
1126  *
1127  */
lms_socket_flushq(MSocket * m)1128 int lms_socket_flushq(MSocket *m)
1129 {
1130 	ssize_t rv;
1131 	ssize_t sl;
1132 	unsigned char *tmpptr;
1133 	size_t tmplen;
1134 
1135 	if (!m)
1136 	{
1137 		errno = EINVAL;
1138 		return(-1);
1139 	}
1140 	if (!(m->flags & LMSFLG_CONNECTED))
1141 	{
1142 		errno = ENOTCONN;
1143 		return(-1);
1144 	}
1145 	if ((m->type != LMSTYPE_STREAM4) && (m->type != LMSTYPE_STREAM6) && (m->type != LMSTYPE_LOCALCLIENT))
1146 	{
1147 		errno = EINVAL;
1148 		return(-1);
1149 	}
1150 	if ((m->sendQ_len == 0) || (m->sendQ_sz == 0))
1151 	{
1152 		return(0);
1153 	}
1154 	if (!m->sendQ)
1155 	{
1156 #ifdef EDOOFUS
1157 		errno = EDOOFUS;
1158 #else
1159 		errno = EINVAL;
1160 #endif
1161 		return(-1);
1162 	}
1163 
1164 	sl = 0;
1165 	tmpptr = m->sendQ;
1166 	tmplen = m->sendQ_len;
1167 	while (tmplen > 0)
1168 	{
1169 		rv = send(m->fd, tmpptr, tmplen, 0);
1170 		if (rv < 0)
1171 		{
1172 			if (sl > 0)
1173 			{
1174 				lms_socket_clearsq(m, sl);
1175 				m->sendQ_len -= sl;
1176 				m->last_send = time(NULL);
1177 			}
1178 			return((int)sl);
1179 		}
1180 		else
1181 		{
1182 			sl += rv;
1183 			tmplen -= rv;
1184 			if (sl < m->sendQ_len)
1185 			{
1186 				tmpptr += rv;
1187 			}
1188 			m->bytes_r += rv;
1189 		}
1190 	}
1191 
1192 	m->sendQ_len = 0;
1193 	free(m->sendQ);
1194 	m->sendQ = (unsigned char *)NULL;
1195 	m->sendQ_sz = 0;
1196 
1197 	m->last_send = time(NULL);
1198 
1199 	return((int)sl);
1200 }
1201 
1202 /*
1203  * lms_socket_appendq() eithers creates the sendQ on a socket, or appends to it
1204  *
1205  * m = the socket
1206  * data = the data to be added to the sendQ
1207  * data_len = the exact length of the data to append to the sendQ
1208  *
1209  */
lms_socket_appendq(MSocket * m,unsigned char * data,size_t data_len)1210 int lms_socket_appendq(MSocket *m, unsigned char *data, size_t data_len)
1211 {
1212 	if (!m)
1213 	{
1214 		errno = EINVAL;
1215 		return(-1);
1216 	}
1217 
1218 	if (m->sendQ_sz > 0)
1219 	{
1220 		if (!m->sendQ)
1221 		{
1222 #ifdef EDOOFUS
1223 			errno = EDOOFUS;
1224 #else
1225 			errno = EINVAL;
1226 #endif
1227 			return(-1);
1228 		}
1229 
1230 #ifdef HAVE_REALLOCF
1231 		m->sendQ = reallocf(m->sendQ, (m->sendQ_sz + data_len));
1232 #else
1233 		m->sendQ = realloc(m->sendQ, (m->sendQ_sz + data_len));
1234 #endif /* HAVE_REALLOCF */
1235 		if (!m->sendQ)
1236 		{
1237 			return(-1);
1238 		}
1239 		m->sendQ_sz += data_len;
1240 		lms_str_ocopy(data, m->sendQ, data_len, m->sendQ_len);
1241 		m->sendQ_len += data_len;
1242 	}
1243 	else
1244 	{
1245 		m->sendQ = (unsigned char *)malloc(data_len);
1246 		if (!m->sendQ)
1247 		{
1248 			return(-1);
1249 		}
1250 		m->sendQ_sz = data_len;
1251 		lms_str_copy(data, m->sendQ, data_len);
1252 		m->sendQ_len = data_len;
1253 	}
1254 
1255 	return(0);
1256 }
1257 
1258 /*
1259  * lms_socket_clearsq() clears bytes from the front of the sendQ of a socket
1260  *
1261  * m = the socket to clear them from the sendQ of
1262  * len = the number of bytes to clear
1263  *
1264  */
lms_socket_clearsq(MSocket * m,ssize_t len)1265 int lms_socket_clearsq(MSocket *m, ssize_t len)
1266 {
1267 	ssize_t newlen;
1268 	unsigned char *p;
1269 
1270 	newlen = (m->sendQ_len - len);
1271 	if (newlen < 0)
1272 	{
1273 		return(-1);
1274 	}
1275 	else if (newlen == 0)
1276 	{
1277 		if (m->sendQ)
1278 		{
1279 			free(m->sendQ);
1280 		}
1281 		m->sendQ_sz = 0;
1282 		m->sendQ_len = 0;
1283 		m->sendQ = (unsigned char *)NULL;
1284 
1285 		return(0);
1286 	}
1287 	p = (unsigned char *)malloc(m->sendQ_len);
1288 	if (!p)
1289 	{
1290 		return(-1);
1291 	}
1292 	memcpy(p, m->sendQ, m->sendQ_len);
1293 #ifdef HAVE_REALLOCF
1294 	m->sendQ = reallocf(m->sendQ, newlen);
1295 #else
1296 	m->sendQ = realloc(m->sendQ, newlen);
1297 #endif /* HAVE_REALLOCF */
1298 	if (!m->sendQ)
1299 	{
1300 		m->sendQ_sz = 0;
1301 		free(p);
1302 		return(-1);
1303 	}
1304 	m->sendQ_sz = newlen;
1305 	memset(m->sendQ, 0, m->sendQ_sz);
1306 	lms_str_ocopy(p, m->sendQ, m->sendQ_sz, len);
1307 
1308 	free(p);
1309 	return(0);
1310 }
1311 
1312 /*
1313  * lms_socket_freerq() frees up the recvQ of a socket once the application is done with it
1314  *
1315  * m = the socket which it's done with the recvQ of
1316  *
1317  */
lms_socket_freerq(MSocket * m)1318 int lms_socket_freerq(MSocket *m)
1319 {
1320 	if (!m)
1321 	{
1322 		errno = EINVAL;
1323 		return(-1);
1324 	}
1325 	if (!m->recvQ)
1326 	{
1327 		m->recvQ_len = 0;
1328 		m->recvQ_sz = 0;
1329 		errno = EINVAL;
1330 		return(-1);
1331 	}
1332 
1333 	m->recvQ_len = 0;
1334 	m->recvQ_sz = 0;
1335 	free(m->recvQ);
1336 	m->recvQ = (unsigned char *)NULL;
1337 
1338 	return(0);
1339 }
1340