]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/configuration/sgconfig-ng/main_thread.cpp
[NY] Simplified SERVCONF interface.
[stg.git] / projects / stargazer / plugins / configuration / sgconfig-ng / main_thread.cpp
1 #include <unistd.h>
2 #include <sys/socket.h>
3 #include <arpa/inet.h>
4
5 #include <cerrno>
6 #include <cstring>
7
8 #include <boost/thread.hpp>
9
10 #include "common.h"
11
12 #include "main_thread.h"
13 #include "config_thread.h"
14
15 MAIN_THREAD::MAIN_THREAD(ADMINS * a, TARIFFS * t, USERS * u, const SETTINGS * s)
16     : running(true),
17       sd(-1),
18       port(44000),
19       maxConnections(60),
20       admins(a),
21       tariffs(t),
22       users(u),
23       settings(s)
24 {
25 }
26
27 MAIN_THREAD::~MAIN_THREAD()
28 {
29 }
30
31 void MAIN_THREAD::operator() ()
32 {
33     if (!InitNetwork()) {
34         return;
35     }
36
37     int counter = 0;
38     while (running) {
39         if (WaitConnection()) {
40             AcceptConnection();
41         }
42         if (counter == 0) {
43             CleanupThreads();
44         }
45         ++counter;
46         counter = counter % 10; // Every 5 sec
47     }
48
49     close(sd);
50 }
51
52 bool MAIN_THREAD::InitNetwork()
53 {
54     struct sockaddr_in listenAddr;
55
56     sd = socket(AF_INET, SOCK_STREAM, 0);
57
58     if (sd < 0) {
59         printfd(__FILE__, "MAIN_THREAD::InitNetwork() Socket creation failed: '%s'\n", strerror(errno));
60         return false;
61     }
62
63     listenAddr.sin_family = AF_INET;
64     listenAddr.sin_port = htons(port);
65     listenAddr.sin_addr.s_addr = INADDR_ANY;
66
67     if (bind(sd, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) < 0) {
68         printfd(__FILE__, "MAIN_THREAD::InitNetwork() Bind failed: '%s'\n", strerror(errno));
69         return false;
70     }
71
72     if(listen(sd, 8) < 0) {
73         printfd(__FILE__, "MAIN_THREAD::InitNetwork() Error starting to listen: '%s'\n", strerror(errno));
74         return false;
75     }
76
77     return true;
78 }
79
80 bool MAIN_THREAD::WaitConnection()
81 {
82     fd_set rfds;
83     FD_ZERO(&rfds);
84     FD_SET(sd, &rfds);
85
86     /* Wait up to five seconds. */
87     struct timeval tv;
88     tv.tv_sec = 1;
89     tv.tv_usec = 0;
90
91     int res = select(sd + 1, &rfds, NULL, NULL, &tv);
92     /* Don't rely on the value of tv now! */
93
94     if (res == -1) {
95         printfd(__FILE__, "MAIN_THREAD::WaitConnection() Select failed: '%s'\n", strerror(errno));
96         return false;
97     }
98
99     if (res && FD_ISSET(sd, &rfds)) {
100         return true;
101     }
102
103     // Timeout
104     return false;
105 }
106
107 void MAIN_THREAD::AcceptConnection()
108 {
109     if (connections.size() >= maxConnections) {
110         CleanupThreads();
111         if (connections.size() >= maxConnections) {
112             return;
113         }
114     }
115
116     struct sockaddr_in remoteAddr;
117     socklen_t len = sizeof(remoteAddr);
118     int newSD = accept(sd, (struct sockaddr *)&remoteAddr, &len);
119
120     if (newSD < 0) {
121         printfd(__FILE__, "MAIN_THREAD::AcceptConnection() Accept failed: '%s'\n", strerror(errno));
122         return;
123     }
124
125     CONFIG_THREAD ct(admins, tariffs, users, settings);
126     ct.SetConnection(newSD, remoteAddr);
127
128     connections.push_back(ct);
129     boost::thread thread(boost::ref(connections.back()));
130     thread.detach();
131 }
132
133 void MAIN_THREAD::CleanupThreads()
134 {
135     connections.remove_if(
136             std::mem_fun_ref(&CONFIG_THREAD::IsDone)
137             );
138     printfd(__FILE__, "MAIN_THREAD::CleanupThreads() Active threads: %d\n", connections.size());
139 }