]> arthur.barton.de Git - netdata.git/blob - src/web_client.c
proper IPv6 handling
[netdata.git] / src / web_client.c
1 #include <stdlib.h>
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <netinet/in.h>
5 #include <arpa/inet.h>
6
7 #include "global_statistics.h"
8 #include "log.h"
9
10 #include "web_client.h"
11
12 #define INITIAL_WEB_DATA_LENGTH 65536
13
14 struct web_client *web_clients = NULL;
15 unsigned long long web_clients_count = 0;
16
17 struct web_client *web_client_create(int listener)
18 {
19         struct web_client *w;
20         
21         w = calloc(1, sizeof(struct web_client));
22         if(!w) {
23                 error("Cannot allocate new web_client memory.");
24                 return NULL;
25         }
26
27         w->id = ++web_clients_count;
28         w->mode = WEB_CLIENT_MODE_NORMAL;
29
30         {
31                 struct sockaddr *sadr;
32                 socklen_t addrlen;
33
34                 sadr = (struct sockaddr*) &w->clientaddr;
35                 addrlen = sizeof(w->clientaddr);
36
37                 w->ifd = accept(listener, sadr, &addrlen);
38                 if (w->ifd == -1) {
39                         error("%llu: Cannot accept new incoming connection.", w->id);
40                         free(w);
41                         return NULL;
42                 }
43                 w->ofd = w->ifd;
44
45                 if(getnameinfo(sadr, addrlen, w->client_ip, NI_MAXHOST, w->client_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
46                         error("Cannot getnameinfo() on received client connection.");
47                         strncpy(w->client_ip,   "UNKNOWN", NI_MAXHOST);
48                         strncpy(w->client_port, "UNKNOWN", NI_MAXSERV);
49                 }
50                 w->client_ip[NI_MAXHOST]   = '\0';
51                 w->client_port[NI_MAXSERV] = '\0';
52
53                 switch(sadr->sa_family) {
54                 case AF_INET:
55                         debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
56                         break;
57                 case AF_INET6:
58                         if(strncmp(w->client_ip, "::ffff:", 7) == 0) {
59                                 strcpy(w->client_ip, &w->client_ip[7]);
60                                 debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
61                         }
62                         debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv6 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
63                         break;
64                 default:
65                         debug(D_WEB_CLIENT_ACCESS, "%llu: New UNKNOWN web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
66                         break;
67                 }
68
69                 int flag = 1;
70                 if(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0) error("%llu: Cannot set SO_KEEPALIVE on socket.", w->id);
71         }
72
73         w->data = web_buffer_create(INITIAL_WEB_DATA_LENGTH);
74         if(!w->data) {
75                 close(w->ifd);
76                 free(w);
77                 return NULL;
78         }
79
80         w->wait_receive = 1;
81
82         if(web_clients) web_clients->prev = w;
83         w->next = web_clients;
84         web_clients = w;
85
86         global_statistics.connected_clients++;
87
88         return(w);
89 }
90
91 struct web_client *web_client_free(struct web_client *w)
92 {
93         struct web_client *n = w->next;
94
95         debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port);
96
97         if(w->prev)     w->prev->next = w->next;
98         if(w->next) w->next->prev = w->prev;
99
100         if(w == web_clients) web_clients = w->next;
101
102         if(w->data) web_buffer_free(w->data);
103         close(w->ifd);
104         if(w->ofd != w->ifd) close(w->ofd);
105         free(w);
106
107         global_statistics.connected_clients--;
108
109         return(n);
110 }