Merge branch 'master' of https://github.com/OpenPLi/enigma2
[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         union // ugly workaround for sizeof(sockaddr) < sizeof(sockaddr_in6) issue
16         {
17                 sockaddr sock;
18                 sockaddr_in sock_in;
19                 sockaddr_in6 sock_in6;
20         } client_addr;
21
22         char straddr[INET6_ADDRSTRLEN];
23
24 #ifdef DEBUG_SERVERSOCKET
25         eDebug("[eServerSocket] incoming connection!");
26 #endif
27
28         clientlen = sizeof(client_addr);
29         clientfd = accept(getDescriptor(), &client_addr.sock, &clientlen);
30         if (clientfd < 0)
31         {
32                 eDebug("[eServerSocket] error on accept: %m");
33                 return;
34         }
35
36         switch(client_addr.sock.sa_family)
37         {
38                 case(PF_LOCAL):
39                 {
40                         strRemoteHost = "(local)";
41                         break;
42                 }
43
44                 case(PF_INET):
45                 {
46                         strRemoteHost = inet_ntop(PF_INET, &client_addr.sock_in.sin_addr, straddr, sizeof(straddr));
47                         break;
48                 }
49
50                 case(PF_INET6):
51                 {
52                         static uint8_t ipv4_mapped_pattern[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
53
54                         if(!memcmp(&client_addr.sock_in6.sin6_addr, ipv4_mapped_pattern, sizeof(ipv4_mapped_pattern)))
55                         {
56                                  // ugly hack to get real ipv4 address without the ::ffff:, inet_ntop doesn't have an option for it
57                                 strRemoteHost = inet_ntop(PF_INET, (sockaddr_in *)&client_addr.sock_in6.sin6_addr.s6_addr[12], straddr, sizeof(straddr));
58                         }
59                         else
60                                 strRemoteHost = inet_ntop(PF_INET6, &client_addr.sock_in6.sin6_addr, straddr, sizeof(straddr));
61
62                         break;
63                 }
64
65                 default:
66                 {
67                         strRemoteHost = "(error)";
68                         break;
69                 }
70         }
71
72         newConnection(clientfd);
73 }
74
75 eServerSocket::eServerSocket(int port, eMainloop *ml): eSocket(ml)
76 {
77         int res;
78         struct addrinfo *addr = NULL;
79         struct addrinfo hints;
80         char portnumber[16];
81
82         okflag = 0;
83         strRemoteHost = "";
84
85         memset(&hints, 0, sizeof(hints));
86         hints.ai_family = AF_UNSPEC; /* both ipv4 and ipv6 */
87         hints.ai_socktype = SOCK_STREAM;
88         hints.ai_protocol = 0; /* any */
89 #ifdef AI_ADDRCONFIG
90         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 */
91 #else
92         hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* AI_ADDRCONFIG is not available */
93 #endif
94         snprintf(portnumber, sizeof(portnumber), "%d", port);
95
96         if ((res = getaddrinfo(NULL, portnumber, &hints, &addr)) || !addr)
97         {
98                 eDebug("[eServerSocket] getaddrinfo: %s", gai_strerror(res));
99                 return;
100         }
101
102         if (startListening(addr) >= 0)
103         {
104                 okflag = 1;
105                 rsn->setRequested(eSocketNotifier::Read);
106         }
107         freeaddrinfo(addr);
108 }
109
110 eServerSocket::eServerSocket(std::string path, eMainloop *ml) : eSocket(ml)
111 {
112         struct sockaddr_un serv_addr_un;
113         struct addrinfo addr;
114
115         okflag = 0;
116         strRemoteHost = "";
117
118         memset(&serv_addr_un, 0, sizeof(serv_addr_un));
119         serv_addr_un.sun_family = AF_LOCAL;
120         strcpy(serv_addr_un.sun_path, path.c_str());
121
122         memset(&addr, 0, sizeof(addr));
123         addr.ai_family = AF_LOCAL;
124         addr.ai_socktype = SOCK_STREAM;
125         addr.ai_protocol = 0; /* any */
126         addr.ai_addr = (struct sockaddr *)&serv_addr_un;
127         addr.ai_addrlen = sizeof(serv_addr_un);
128
129         unlink(path.c_str());
130
131         if (startListening(&addr) >= 0)
132         {
133                 okflag = 1;
134                 rsn->setRequested(eSocketNotifier::Read);
135         }
136 }
137
138 eServerSocket::~eServerSocket()
139 {
140 #ifdef DEBUG_SERVERSOCKET
141         eDebug("[eServerSocket] destructed");
142 #endif
143 }
144
145 int eServerSocket::startListening(struct addrinfo *addr)
146 {
147         struct addrinfo *ptr;
148
149         for (ptr = addr; ptr != NULL; ptr = ptr->ai_next)
150         {
151                 if (setSocket(socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol), 1) < 0)
152                 {
153                         continue;
154                 }
155
156                 int val = 1;
157                 setsockopt(getDescriptor(), SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
158
159                 if (bind(getDescriptor(), ptr->ai_addr, ptr->ai_addrlen) < 0)
160                 {
161                         eDebug("[eServerSocket] ERROR on bind: %m");
162                         close();
163                         continue;
164                 }
165         }
166
167         if (getDescriptor() < 0)
168         {
169                 return -1;
170         }
171
172         if (listen(getDescriptor(), 0) < 0)
173         {
174                 close();
175                 return -1;
176         }
177         return 0;
178 }
179
180 int eServerSocket::bind(int sockfd, struct sockaddr *addr, socklen_t addrlen)
181 {
182         int result;
183         while (1)
184         {
185                 if ((result = ::bind(sockfd, addr, addrlen)) < 0 && errno == EINTR) continue;
186                 break;
187         }
188         return result;
189 }
190
191 int eServerSocket::listen(int sockfd, int backlog)
192 {
193         int result;
194         while (1)
195         {
196                 if ((result = ::listen(sockfd, backlog)) < 0 && errno == EINTR) continue;
197                 break;
198         }
199         return result;
200 }
201
202 int eServerSocket::accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
203 {
204         int result;
205         while (1)
206         {
207                 if ((result = ::accept(sockfd, addr, addrlen)) < 0 && errno == EINTR) continue;
208                 break;
209         }
210         return result;
211 }