socket: use getaddrinfo
[openblackhole/openblackhole-enigma2.git] / lib / network / serversocket.cpp
1 #include <errno.h>
2 #include <string.h>
3 #include <lib/network/serversocket.h>
4 #include <arpa/inet.h>
5
6 bool eServerSocket::ok()
7 {
8         return okflag;
9 }
10
11 void eServerSocket::notifier(int)
12 {
13         int clientfd;
14         socklen_t clientlen;
15         struct sockaddr client_addr;
16         char straddr[INET6_ADDRSTRLEN];
17
18 #ifdef DEBUG_SERVERSOCKET
19         eDebug("[eServerSocket] incoming connection!");
20 #endif
21
22         clientlen = sizeof(client_addr);
23         clientfd = accept(getDescriptor(), &client_addr, &clientlen);
24         if (clientfd < 0)
25         {
26                 eDebug("[eServerSocket] error on accept: %m");
27                 return;
28         }
29
30         if (client_addr.sa_family == AF_LOCAL)
31         {
32                 strRemoteHost = "(local)";
33         }
34         else
35         {
36                 strRemoteHost = inet_ntop(client_addr.sa_family, client_addr.sa_data, straddr, sizeof(straddr));
37         }
38         newConnection(clientfd);
39 }
40
41 eServerSocket::eServerSocket(int port, eMainloop *ml): eSocket(ml)
42 {
43         int res;
44         struct addrinfo *addr = NULL;
45         struct addrinfo hints;
46         char portnumber[16];
47
48         okflag = 0;
49         strRemoteHost = "";
50
51         memset(&hints, 0, sizeof(hints));
52         hints.ai_family = AF_UNSPEC; /* both ipv4 and ipv6 */
53         hints.ai_socktype = SOCK_STREAM;
54         hints.ai_protocol = 0; /* any */
55 #ifdef AI_ADDRCONFIG
56         hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_ADDRCONFIG; /* only return ipv6 if we have an ipv6 address ourselves, and ipv4 if we have an ipv4 address ourselves */
57 #else
58         hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* AI_ADDRCONFIG is not available */
59 #endif
60         snprintf(portnumber, sizeof(portnumber), "%d", port);
61
62         if ((res = getaddrinfo(NULL, portnumber, &hints, &addr)) || !addr)
63         {
64                 eDebug("[eServerSocket] getaddrinfo: %s", gai_strerror(res));
65                 return;
66         }
67
68         if (startListening(addr) >= 0)
69         {
70                 okflag = 1;
71                 rsn->setRequested(eSocketNotifier::Read);
72         }
73         freeaddrinfo(addr);
74 }
75
76 eServerSocket::eServerSocket(std::string path, eMainloop *ml) : eSocket(ml)
77 {
78         int res;
79         struct sockaddr_un serv_addr_un;
80         struct addrinfo addr;
81
82         okflag = 0;
83         strRemoteHost = "";
84
85         memset(&serv_addr_un, 0, sizeof(serv_addr_un));
86         serv_addr_un.sun_family = AF_LOCAL;
87         strcpy(serv_addr_un.sun_path, path.c_str());
88
89         memset(&addr, 0, sizeof(addr));
90         addr.ai_family = AF_LOCAL;
91         addr.ai_socktype = SOCK_STREAM;
92         addr.ai_protocol = 0; /* any */
93         addr.ai_addr = (struct sockaddr *)&serv_addr_un;
94         addr.ai_addrlen = sizeof(serv_addr_un);
95
96         unlink(path.c_str());
97
98         if (startListening(&addr) >= 0)
99         {
100                 okflag = 1;
101                 rsn->setRequested(eSocketNotifier::Read);
102         }
103 }
104
105 eServerSocket::~eServerSocket()
106 {
107 #ifdef DEBUG_SERVERSOCKET
108         eDebug("[eServerSocket] destructed");
109 #endif
110 }
111
112 int eServerSocket::startListening(struct addrinfo *addr)
113 {
114         struct addrinfo *ptr = addr;
115         for (ptr = addr; ptr != NULL; ptr = ptr->ai_next)
116         {
117                 if (setSocket(socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol), 1) < 0)
118                 {
119                         continue;
120                 }
121
122                 int val = 1;
123                 setsockopt(getDescriptor(), SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
124
125                 if (bind(getDescriptor(), ptr->ai_addr, ptr->ai_addrlen) < 0)
126                 {
127                         eDebug("[eServerSocket] ERROR on bind: %m");
128                         close();
129                         continue;
130                 }
131         }
132
133         if (getDescriptor() < 0)
134         {
135                 return -1;
136         }
137
138         if (listen(getDescriptor(), 0) < 0)
139         {
140                 close();
141                 return -1;
142         }
143         return 0;
144 }
145
146 int eServerSocket::bind(int sockfd, struct sockaddr *addr, socklen_t addrlen)
147 {
148         int result;
149         while (1)
150         {
151                 if ((result = ::bind(sockfd, addr, addrlen)) < 0 && errno == EINTR) continue;
152                 break;
153         }
154         return result;
155 }
156
157 int eServerSocket::listen(int sockfd, int backlog)
158 {
159         int result;
160         while (1)
161         {
162                 if ((result = ::listen(sockfd, backlog)) < 0 && errno == EINTR) continue;
163                 break;
164         }
165         return result;
166 }
167
168 int eServerSocket::accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
169 {
170         int result;
171         while (1)
172         {
173                 if ((result = ::accept(sockfd, addr, addrlen)) < 0 && errno == EINTR) continue;
174                 break;
175         }
176         return result;
177 }