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