Line data Source code
1 : /*!
2 : * \file
3 : * \author Christopher Stender
4 : * \date 2018-02-15
5 : * \version 0.1
6 : *
7 : * \brief Networking helper functions
8 : *
9 : * \details
10 : * This module collects networking helper functions like tcp_start_server().
11 : *
12 : *\copyright
13 : * Copyright (c) 2023 Fraunhofer IIS
14 : *
15 : * Permission is hereby granted, free of charge, to any person obtaining a copy
16 : * of this software and associated documentation files (the “Software”), to deal
17 : * in the Software without restriction, including without limitation the rights
18 : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 : * copies of the Software, and to permit persons to whom the Software is
20 : * furnished to do so, subject to the following conditions:
21 : *
22 : * The above copyright notice and this permission notice shall be included in
23 : * all copies or substantial portions of the Software.
24 : *
25 : * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 : * THE SOFTWARE.
32 : */
33 :
34 : #include <stdio.h>
35 : #include <string.h>
36 : #include <sys/types.h>
37 : #include <sys/socket.h>
38 : #include <netdb.h>
39 : #include <unistd.h>
40 :
41 : #include "networking.h"
42 :
43 : /* taken from getaddrinfo manpage and slightly adapted */
44 0 : static int tcp_start_server_on_addr_family(const char* port, int ai_family)
45 : {
46 : struct addrinfo hints;
47 : struct addrinfo *result, *rp;
48 : int sfd, s;
49 :
50 0 : memset(&hints, 0, sizeof(struct addrinfo));
51 0 : hints.ai_family = ai_family; /* Address family specified by user */
52 0 : hints.ai_socktype = SOCK_STREAM; /* Stream socket */
53 0 : hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
54 0 : hints.ai_protocol = 0; /* Any protocol */
55 0 : hints.ai_canonname = NULL;
56 0 : hints.ai_addr = NULL;
57 0 : hints.ai_next = NULL;
58 :
59 0 : s = getaddrinfo(NULL, port, &hints, &result);
60 0 : if (s != 0) {
61 0 : fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
62 0 : return -1;
63 : }
64 :
65 : /* getaddrinfo() returns a list of address structures.
66 : Try each address until we successfully bind(2).
67 : If socket(2) (or bind(2)) fails, we (close the socket
68 : and) try the next address. */
69 :
70 0 : for (rp = result; rp != NULL; rp = rp->ai_next) {
71 0 : sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
72 0 : if (sfd == -1)
73 0 : continue;
74 :
75 : /* Sometimes after a server shutdown the server socket can get
76 : into TIME_WAIT state and it is no longer possible to use it again.
77 : With SO_REUSEADDR enabled, the server socket can be reused
78 : instantaneously after a shutdown. setsockopt() needs to be called
79 : before bind. */
80 :
81 0 : int reuse = 1; /* Set SO_REUSEADDR to 1(True) */
82 0 : if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
83 0 : perror("ERROR: setsocktop");
84 0 : fprintf(stderr, "WARNING: Reuse of server socket wont be possible. \n");
85 : /* The programm can go on. */
86 : };
87 :
88 0 : if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
89 0 : break; /* Success */
90 :
91 0 : close(sfd);
92 : }
93 :
94 0 : freeaddrinfo(result); /* No longer needed */
95 :
96 0 : if (rp == NULL) { /* No address succeeded */
97 0 : fprintf(stderr, "Could not bind\n");
98 0 : return -1;
99 : }
100 :
101 0 : return sfd;
102 : }
103 :
104 0 : int tcp_start_server(const char* port)
105 : {
106 0 : return tcp_start_server_on_addr_family(port, AF_UNSPEC);
107 : }
108 :
109 0 : int tcp4_start_server(const char* port)
110 : {
111 0 : return tcp_start_server_on_addr_family(port, AF_INET);
112 : }
113 :
114 0 : int tcp6_start_server(const char* port)
115 : {
116 0 : return tcp_start_server_on_addr_family(port, AF_INET6);
117 : }
118 :
|