1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 Kannel Group
5 * Copyright (c) 1998-2001 WapIT Ltd.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Kannel Group (http://www.kannel.org/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Kannel" and "Kannel Group" must not be used to
28 * endorse or promote products derived from this software without
29 * prior written permission. For written permission, please
30 * contact org@kannel.org.
31 *
32 * 5. Products derived from this software may not be called "Kannel",
33 * nor may "Kannel" appear in their name, without prior written
34 * permission of the Kannel Group.
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Kannel Group. For more information on
51 * the Kannel Group, please see <http://www.kannel.org/>.
52 *
53 * Portions of this software are based upon software originally written at
54 * WapIT Ltd., Helsinki, Finland for the Kannel project.
55 */
56
57 #include <ctype.h>
58 #include <errno.h>
59 #include <stdarg.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <time.h>
64 #include <unistd.h>
65 #include <fcntl.h>
66
67 #include <sys/time.h>
68 #include <sys/types.h>
69 #include <sys/socket.h>
70 #include <netinet/in.h>
71 #include <netdb.h>
72 #include <arpa/inet.h>
73 #include <sys/utsname.h>
74
75 #include "gwlib.h"
76
77
78 static Octstr *official_name = NULL;
79 static Octstr *official_ip = NULL;
80
81 /*
82 * FreeBSD is not happy with our approach of allocating a sockaddr
83 * and then filling in the fields. It has private fields that need
84 * to be initialized to 0. This structure is used for that.
85 */
86 static const struct sockaddr_in empty_sockaddr_in;
87
88 #ifndef UDP_PACKET_MAX_SIZE
89 #define UDP_PACKET_MAX_SIZE (64*1024)
90 #endif
91
92
make_server_socket(int port,const char * interface_name)93 int make_server_socket(int port, const char *interface_name)
94 {
95 struct sockaddr_in addr;
96 int s;
97 int reuse;
98 struct hostent hostinfo;
99 char *buff = NULL;
100
101 s = socket(PF_INET, SOCK_STREAM, 0);
102 if (s == -1) {
103 error(errno, "socket failed");
104 goto error;
105 }
106
107 addr = empty_sockaddr_in;
108 addr.sin_family = AF_INET;
109 addr.sin_port = htons(port);
110 if (interface_name == NULL || strcmp(interface_name, "*") == 0)
111 addr.sin_addr.s_addr = htonl(INADDR_ANY);
112 else {
113 if (gw_gethostbyname(&hostinfo, interface_name, &buff) == -1) {
114 error(errno, "gethostbyname failed");
115 goto error;
116 }
117 addr.sin_addr = *(struct in_addr *) hostinfo.h_addr;
118 }
119
120 reuse = 1;
121 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse,
122 sizeof(reuse)) == -1) {
123 error(errno, "setsockopt failed for server address");
124 goto error;
125 }
126
127 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
128 error(errno, "bind failed");
129 goto error;
130 }
131
132 if (listen(s, 10) == -1) {
133 error(errno, "listen failed");
134 goto error;
135 }
136
137 gw_free(buff);
138
139 return s;
140
141 error:
142 if (s >= 0)
143 (void) close(s);
144 gw_free(buff);
145 return -1;
146 }
147
148
tcpip_connect_to_server(char * hostname,int port,const char * source_addr)149 int tcpip_connect_to_server(char *hostname, int port, const char *source_addr)
150 {
151
152 return tcpip_connect_to_server_with_port(hostname, port, 0, source_addr);
153 }
154
155
tcpip_connect_to_server_with_port(char * hostname,int port,int our_port,const char * source_addr)156 int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr)
157 {
158 struct sockaddr_in addr;
159 struct sockaddr_in o_addr;
160 struct hostent hostinfo;
161 struct hostent o_hostinfo;
162 int s, rc = -1, i;
163 char *buff, *buff1;
164
165 buff = buff1 = NULL;
166
167 s = socket(PF_INET, SOCK_STREAM, 0);
168 if (s == -1) {
169 error(errno, "Couldn't create new socket.");
170 goto error;
171 }
172
173 if (gw_gethostbyname(&hostinfo, hostname, &buff) == -1) {
174 error(errno, "gethostbyname failed");
175 goto error;
176 }
177
178 if (our_port > 0 || (source_addr != NULL && strcmp(source_addr, "*") != 0)) {
179 int reuse;
180
181 o_addr = empty_sockaddr_in;
182 o_addr.sin_family = AF_INET;
183 o_addr.sin_port = htons(our_port);
184 if (source_addr == NULL || strcmp(source_addr, "*") == 0)
185 o_addr.sin_addr.s_addr = htonl(INADDR_ANY);
186 else {
187 if (gw_gethostbyname(&o_hostinfo, source_addr, &buff1) == -1) {
188 error(errno, "gethostbyname failed");
189 goto error;
190 }
191 o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr;
192 }
193
194 reuse = 1;
195 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) {
196 error(errno, "setsockopt failed before bind");
197 goto error;
198 }
199 if (bind(s, (struct sockaddr *) &o_addr, sizeof(o_addr)) == -1) {
200 error(errno, "bind to local port %d failed", our_port);
201 goto error;
202 }
203 }
204
205 i = 0;
206 do {
207 Octstr *ip2;
208
209 addr = empty_sockaddr_in;
210 addr.sin_family = AF_INET;
211 addr.sin_port = htons(port);
212 addr.sin_addr = *(struct in_addr *) hostinfo.h_addr_list[i];
213
214 ip2 = gw_netaddr_to_octstr(AF_INET, &addr.sin_addr);
215
216 debug("gwlib.socket", 0, "Connecting to <%s>", octstr_get_cstr(ip2));
217
218 rc = connect(s, (struct sockaddr *) &addr, sizeof(addr));
219 if (rc == -1) {
220 error(errno, "connect to <%s> failed", octstr_get_cstr(ip2));
221 }
222 octstr_destroy(ip2);
223 } while (rc == -1 && hostinfo.h_addr_list[++i] != NULL);
224
225 if (rc == -1)
226 goto error;
227
228 gw_free(buff);
229 gw_free(buff1);
230 return s;
231
232 error:
233 error(0, "error connecting to server `%s' at port `%d'", hostname, port);
234 if (s >= 0)
235 close(s);
236 gw_free(buff);
237 gw_free(buff1);
238 return -1;
239 }
240
tcpip_connect_nb_to_server(char * hostname,int port,const char * source_addr,int * done)241 int tcpip_connect_nb_to_server(char *hostname, int port, const char *source_addr, int *done)
242 {
243 return tcpip_connect_nb_to_server_with_port(hostname, port, 0, source_addr, done);
244 }
245
tcpip_connect_nb_to_server_with_port(char * hostname,int port,int our_port,const char * source_addr,int * done)246 int tcpip_connect_nb_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr, int *done)
247 {
248 struct sockaddr_in addr;
249 struct sockaddr_in o_addr;
250 struct hostent hostinfo;
251 struct hostent o_hostinfo;
252 int s, flags, rc = -1, i;
253 char *buff, *buff1;
254
255 *done = 1;
256 buff = buff1 = NULL;
257
258 s = socket(PF_INET, SOCK_STREAM, 0);
259 if (s == -1) {
260 error(errno, "Couldn't create new socket.");
261 goto error;
262 }
263
264 if (gw_gethostbyname(&hostinfo, hostname, &buff) == -1) {
265 error(errno, "gethostbyname failed");
266 goto error;
267 }
268
269 if (our_port > 0 || (source_addr != NULL && strcmp(source_addr, "*") != 0)) {
270 int reuse;
271
272 o_addr = empty_sockaddr_in;
273 o_addr.sin_family = AF_INET;
274 o_addr.sin_port = htons(our_port);
275 if (source_addr == NULL || strcmp(source_addr, "*") == 0)
276 o_addr.sin_addr.s_addr = htonl(INADDR_ANY);
277 else {
278 if (gw_gethostbyname(&o_hostinfo, source_addr, &buff1) == -1) {
279 error(errno, "gethostbyname failed");
280 goto error;
281 }
282 o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr;
283 }
284
285 reuse = 1;
286 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) {
287 error(errno, "setsockopt failed before bind");
288 goto error;
289 }
290 if (bind(s, (struct sockaddr *) &o_addr, sizeof(o_addr)) == -1) {
291 error(errno, "bind to local port %d failed", our_port);
292 goto error;
293 }
294 }
295
296 flags = fcntl(s, F_GETFL, 0);
297 fcntl(s, F_SETFL, flags | O_NONBLOCK);
298
299 i = 0;
300 do {
301 Octstr *ip2;
302
303 addr = empty_sockaddr_in;
304 addr.sin_family = AF_INET;
305 addr.sin_port = htons(port);
306 addr.sin_addr = *(struct in_addr *) hostinfo.h_addr_list[i];
307
308 ip2 = gw_netaddr_to_octstr(AF_INET, &addr.sin_addr);
309
310 debug("gwlib.socket", 0, "Connecting nonblocking to <%s>", octstr_get_cstr(ip2));
311
312 if ((rc = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) {
313 if (errno != EINPROGRESS) {
314 error(errno, "nonblocking connect to <%s> failed", octstr_get_cstr(ip2));
315 }
316 }
317 octstr_destroy(ip2);
318 } while (rc == -1 && errno != EINPROGRESS && hostinfo.h_addr_list[++i] != NULL);
319
320 if (rc == -1 && errno != EINPROGRESS)
321 goto error;
322
323 /* May be connected immediatly
324 * (if we connecting to localhost for example)
325 */
326 if (rc == 0) {
327 *done = 0;
328 }
329
330 gw_free(buff);
331 gw_free(buff1);
332
333 return s;
334
335 error:
336 error(0, "error connecting to server `%s' at port `%d'", hostname, port);
337 if (s >= 0)
338 close(s);
339 gw_free(buff);
340 gw_free(buff1);
341 return -1;
342 }
343
344
write_to_socket(int socket,char * str)345 int write_to_socket(int socket, char *str)
346 {
347 size_t len;
348 int ret;
349
350 len = strlen(str);
351 while (len > 0) {
352 ret = write(socket, str, len);
353 if (ret == -1) {
354 if (errno == EAGAIN) continue;
355 if (errno == EINTR) continue;
356 error(errno, "Writing to socket failed");
357 return -1;
358 }
359 /* ret may be less than len, if the writing was interrupted
360 by a signal. */
361 len -= ret;
362 str += ret;
363 }
364 return 0;
365 }
366
367
socket_set_blocking(int fd,int blocking)368 int socket_set_blocking(int fd, int blocking)
369 {
370 int flags, newflags;
371
372 flags = fcntl(fd, F_GETFL);
373 if (flags < 0) {
374 error(errno, "cannot get flags for fd %d", fd);
375 return -1;
376 }
377
378 if (blocking)
379 newflags = flags & ~O_NONBLOCK;
380 else
381 newflags = flags | O_NONBLOCK;
382
383 if (newflags != flags) {
384 if (fcntl(fd, F_SETFL, newflags) < 0) {
385 error(errno, "cannot set flags for fd %d", fd);
386 return -1;
387 }
388 }
389
390 return 0;
391 }
392
393
socket_set_nodelay(int fd,int on)394 int socket_set_nodelay(int fd, int on)
395 {
396 int rc;
397
398 rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on));
399 if (rc == -1)
400 error(errno, "Unable set TCP_NODELAY(%d)", on);
401
402 return rc;
403 }
404
405
read_available(int fd,long wait_usec)406 int read_available(int fd, long wait_usec)
407 {
408 fd_set rf;
409 struct timeval to;
410 int ret;
411 div_t waits;
412
413 gw_assert(fd >= 0);
414
415 FD_ZERO(&rf);
416 FD_SET(fd, &rf);
417 waits = div(wait_usec, 1000000);
418 to.tv_sec = waits.quot;
419 to.tv_usec = waits.rem;
420 retry:
421 ret = select(fd + 1, &rf, NULL, NULL, &to);
422 if (ret > 0 && FD_ISSET(fd, &rf))
423 return 1;
424 if (ret < 0) {
425 /* In most select() implementations, to will now contain the
426 * remaining time rather than the original time. That is exactly
427 * what we want when retrying after an interrupt. */
428 switch (errno) {
429 /*The first two entries here are OK*/
430 case EINTR:
431 goto retry;
432 case EAGAIN:
433 return 1;
434 /* We are now sucking mud, figure things out here
435 * as much as possible before it gets lost under
436 * layers of abstraction. */
437 case EBADF:
438 if (!FD_ISSET(fd, &rf)) {
439 warning(0, "Tried to select on fd %d, not in the set!\n", fd);
440 } else {
441 warning(0, "Tried to select on invalid fd %d!\n", fd);
442 }
443 break;
444 case EINVAL:
445 /* Solaris catchall "It didn't work" error, lets apply
446 * some tests and see if we can catch it. */
447
448 /* First up, try invalid timeout*/
449 if (to.tv_sec > 10000000)
450 warning(0, "Wait more than three years for a select?\n");
451 if (to.tv_usec > 1000000)
452 warning(0, "There are only 1000000 usec in a second...\n");
453 break;
454
455
456 }
457 return -1; /* some error */
458 }
459 return 0;
460 }
461
462
463
udp_client_socket(void)464 int udp_client_socket(void)
465 {
466 int s;
467
468 s = socket(PF_INET, SOCK_DGRAM, 0);
469 if (s == -1) {
470 error(errno, "Couldn't create a UDP socket");
471 return -1;
472 }
473
474 return s;
475 }
476
477
udp_bind(int port,const char * source_addr)478 int udp_bind(int port, const char *source_addr)
479 {
480 int s;
481 struct sockaddr_in sa;
482 struct hostent hostinfo;
483 char *buff = NULL;
484
485 s = socket(PF_INET, SOCK_DGRAM, 0);
486 if (s == -1) {
487 error(errno, "Couldn't create a UDP socket");
488 return -1;
489 }
490
491 sa = empty_sockaddr_in;
492 sa.sin_family = AF_INET;
493 sa.sin_port = htons(port);
494 if (strcmp(source_addr, "*") == 0)
495 sa.sin_addr.s_addr = htonl(INADDR_ANY);
496 else {
497 if (gw_gethostbyname(&hostinfo, source_addr, &buff) == -1) {
498 error(errno, "gethostbyname failed");
499 gw_free(buff);
500 return -1;
501 }
502 sa.sin_addr = *(struct in_addr *) hostinfo.h_addr;
503 }
504
505 if (bind(s, (struct sockaddr *) &sa, (int) sizeof(sa)) == -1) {
506 error(errno, "Couldn't bind a UDP socket to port %d", port);
507 (void) close(s);
508 return -1;
509 }
510
511 gw_free(buff);
512
513 return s;
514 }
515
516
udp_create_address(Octstr * host_or_ip,int port)517 Octstr *udp_create_address(Octstr *host_or_ip, int port)
518 {
519 struct sockaddr_in sa;
520 struct hostent h;
521 char *buff = NULL;
522 Octstr *ret;
523
524 sa = empty_sockaddr_in;
525 sa.sin_family = AF_INET;
526 sa.sin_port = htons(port);
527
528 if (strcmp(octstr_get_cstr(host_or_ip), "*") == 0) {
529 sa.sin_addr.s_addr = INADDR_ANY;
530 } else {
531 if (gw_gethostbyname(&h, octstr_get_cstr(host_or_ip), &buff) == -1) {
532 error(0, "Couldn't find the IP number of `%s'",
533 octstr_get_cstr(host_or_ip));
534 gw_free(buff);
535 return NULL;
536 }
537 sa.sin_addr = *(struct in_addr *) h.h_addr;
538 }
539
540 ret = octstr_create_from_data((char *) &sa, sizeof(sa));
541 gw_free(buff);
542
543 return ret;
544 }
545
546
udp_get_port(Octstr * addr)547 int udp_get_port(Octstr *addr)
548 {
549 struct sockaddr_in sa;
550
551 gw_assert(octstr_len(addr) == sizeof(sa));
552 memcpy(&sa, octstr_get_cstr(addr), sizeof(sa));
553 return ntohs(sa.sin_port);
554 }
555
556
udp_get_ip(Octstr * addr)557 Octstr *udp_get_ip(Octstr *addr)
558 {
559 struct sockaddr_in sa;
560
561 gw_assert(octstr_len(addr) == sizeof(sa));
562 memcpy(&sa, octstr_get_cstr(addr), sizeof(sa));
563 return gw_netaddr_to_octstr(AF_INET, &sa.sin_addr);
564 }
565
566
udp_sendto(int s,Octstr * datagram,Octstr * addr)567 int udp_sendto(int s, Octstr *datagram, Octstr *addr)
568 {
569 struct sockaddr_in sa;
570
571 gw_assert(octstr_len(addr) == sizeof(sa));
572 memcpy(&sa, octstr_get_cstr(addr), sizeof(sa));
573 if (sendto(s, octstr_get_cstr(datagram), octstr_len(datagram), 0,
574 (struct sockaddr *) &sa, (int) sizeof(sa)) == -1) {
575 error(errno, "Couldn't send UDP packet");
576 return -1;
577 }
578 return 0;
579 }
580
581
udp_recvfrom(int s,Octstr ** datagram,Octstr ** addr)582 int udp_recvfrom(int s, Octstr **datagram, Octstr **addr)
583 {
584 return udp_recvfrom_flags(s, datagram, addr, 0);
585 }
586
587
udp_recvfrom_flags(int s,Octstr ** datagram,Octstr ** addr,int sockrcvflags)588 int udp_recvfrom_flags(int s, Octstr **datagram, Octstr **addr, int sockrcvflags)
589 {
590 struct sockaddr_in sa;
591 socklen_t salen;
592 char *buf;
593 int bytes;
594
595 buf = gw_malloc(UDP_PACKET_MAX_SIZE);
596
597 salen = sizeof(sa);
598 bytes = recvfrom(s, buf, UDP_PACKET_MAX_SIZE, sockrcvflags, (struct sockaddr *) &sa, &salen);
599 if (bytes == -1) {
600 if (errno != EAGAIN)
601 error(errno, "Couldn't receive UDP packet");
602 gw_free(buf);
603 return -1;
604 }
605
606 *datagram = octstr_create_from_data(buf, bytes);
607 *addr = octstr_create_from_data((char *) &sa, salen);
608
609 gw_free(buf);
610
611 return 0;
612 }
613
614
host_ip(struct sockaddr_in addr)615 Octstr *host_ip(struct sockaddr_in addr)
616 {
617 return gw_netaddr_to_octstr(AF_INET, &addr.sin_addr);
618 }
619
620
host_port(struct sockaddr_in addr)621 int host_port(struct sockaddr_in addr)
622 {
623 return ntohs(addr.sin_port);
624 }
625
626
get_official_name(void)627 Octstr *get_official_name(void)
628 {
629 gw_assert(official_name != NULL);
630 return official_name;
631 }
632
633
get_official_ip(void)634 Octstr *get_official_ip(void)
635 {
636 gw_assert(official_ip != NULL);
637 return official_ip;
638 }
639
640
setup_official_name(void)641 static void setup_official_name(void)
642 {
643 struct utsname u;
644 struct hostent h;
645 char *buff = NULL;
646
647 gw_assert(official_name == NULL);
648 if (uname(&u) == -1)
649 panic(0, "uname failed - can't happen, unless " GW_NAME " is buggy.");
650 if (gw_gethostbyname(&h, u.nodename, &buff) == -1) {
651 error(0, "Can't find out official hostname for this host, "
652 "using `%s' instead.", u.nodename);
653 official_name = octstr_create(u.nodename);
654 official_ip = octstr_create("127.0.0.1");
655 } else {
656 official_name = octstr_create(h.h_name);
657 official_ip = gw_netaddr_to_octstr(AF_INET, h.h_addr);
658 }
659 gw_free(buff);
660 }
661
662
socket_init(void)663 void socket_init(void)
664 {
665 setup_official_name();
666 }
667
socket_shutdown(void)668 void socket_shutdown(void)
669 {
670 octstr_destroy(official_name);
671 official_name = NULL;
672 octstr_destroy(official_ip);
673 official_ip = NULL;
674 }
675
676
gw_netaddr_to_octstr(int af,void * src)677 Octstr *gw_netaddr_to_octstr(int af, void *src)
678 {
679 switch (af) {
680 case AF_INET: {
681 char straddr[INET_ADDRSTRLEN];
682 inet_ntop(AF_INET, src, straddr, sizeof(straddr));
683 return octstr_create(straddr);
684 }
685
686 #ifdef AF_INET6
687 case AF_INET6: {
688 char straddr[INET6_ADDRSTRLEN];
689 inet_ntop(AF_INET6, src, straddr, sizeof(straddr));
690 return octstr_create(straddr);
691 }
692 #endif
693
694 default:
695 return NULL;
696 }
697 }
698
699
gw_accept(int fd,Octstr ** client_addr)700 int gw_accept(int fd, Octstr **client_addr)
701 {
702 struct sockaddr_in addr;
703 socklen_t addrlen;
704 int new_fd;
705
706 if (gwthread_pollfd(fd, POLLIN, -1.0) != POLLIN) {
707 debug("gwlib.socket", 0, "gwthread_pollfd interrupted or failed");
708 return -1;
709 }
710 addrlen = sizeof(addr);
711 new_fd = accept(fd, (struct sockaddr *) &addr, &addrlen);
712 if (new_fd == -1) {
713 error(errno, "accept system call failed.");
714 return -1;
715 }
716 *client_addr = host_ip(addr);
717 debug("test_smsc", 0, "accept() succeeded, client from %s",
718 octstr_get_cstr(*client_addr));
719 return new_fd;
720 }
721