2 Copyright (C) 2010-2011 jeanfi@gmail.com
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 #include <sys/types.h>
26 #include <sys/select.h>
27 #include <sys/socket.h>
32 #include <microhttpd.h>
33 #include <json/json.h>
36 #include <glibtop/cpu.h>
53 #define DEFAULT_PORT 3131
56 #define PAGE_NOT_FOUND \
57 "<html><body><p>Page not found - Go to <a href='/index.lua'>Main page</a>\
61 #define PSENSOR_SERVER_OPTIONS " --help display this help and exit\n\
62 --version output version information and exit\n\
63 --port=PORT webserver port\n\
64 --wdir=DIR directory containing webserver pages"
66 #define PSENSOR_SERVER_USAGE "Usage: psensor-server [OPTION]"
68 #define PSENSOR_SERVER_DESCRIPTION \
69 "HTTP server for retrieving hardware temperatures."
71 #define PSENSOR_SERVER_CONTACT "Report bugs to: psensor@wpitchoune.net\n\
72 Psensor home page: <http://wpitchoune.net/psensor/>"
74 #define PSENSOR_SERVER_COPYRIGHT \
75 "Copyright (C) 2010-2011 jeanfi@gmail.com\n\
76 License GPLv2: GNU GPL version 2 or later \
77 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n\
78 This is free software: you are free to change and redistribute it.\n\
79 There is NO WARRANTY, to the extent permitted by law."
81 #define OPT_PORT "port"
82 #define OPT_HELP "help"
83 #define OPT_VERSION "version"
84 #define OPT_WWW_DIR "wdir"
86 static struct option long_options[] = {
87 {OPT_VERSION, no_argument, 0, 'v'},
88 {OPT_HELP, no_argument, 0, 'h'},
89 {OPT_PORT, required_argument, 0, 'p'},
90 {OPT_WWW_DIR, required_argument, 0, 'w'},
94 static char *www_dir = DEFAULT_WWW_DIR;
97 static float cpu_rate;
98 static glibtop_cpu *cpu;
101 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
103 json_object *sensor_to_json_object(struct psensor *s)
106 json_object *obj = json_object_new_object();
109 json_object_object_add(obj, "id", json_object_new_string(s->id));
110 json_object_object_add(obj, "name", json_object_new_string(s->name));
111 json_object_object_add(obj, "type", json_object_new_int(s->type));
112 json_object_object_add(obj, "min", json_object_new_double(s->min));
113 json_object_object_add(obj, "max", json_object_new_double(s->max));
115 m = psensor_get_current_measure(s);
116 mo = json_object_new_object();
117 json_object_object_add(mo, "value", json_object_new_double(m->value));
118 json_object_object_add(mo, "time",
119 json_object_new_int((m->time).tv_sec));
120 json_object_object_add(obj, "last_measure", mo);
125 char *sensor_to_json_string(struct psensor *s)
128 json_object *obj = sensor_to_json_object(s);
130 str = strdup(json_object_to_json_string(obj));
132 json_object_put(obj);
137 char *sensors_to_json_string(struct psensor **sensors)
139 struct psensor **sensors_cur;
142 json_object *obj = json_object_new_array();
144 sensors_cur = sensors;
146 while (*sensors_cur) {
147 struct psensor *s = *sensors_cur;
149 json_object_array_add(obj, sensor_to_json_object(s));
154 str = strdup(json_object_to_json_string(obj));
156 json_object_put(obj);
161 char *lua_to_html_page(struct psensor **sensors, const char *url)
163 struct psensor **s_cur;
168 lua_State *L = lua_open(); /* create state */
177 lua_pushstring(L, "load");
178 lua_pushnumber(L, cpu_rate);
180 lua_setglobal(L, "cpu");
189 lua_pushinteger(L, i);
193 lua_pushstring(L, "name");
194 lua_pushstring(L, (*s_cur)->name);
197 lua_pushstring(L, "measure_last");
198 lua_pushnumber(L, psensor_get_current_value(*s_cur));
201 lua_pushstring(L, "measure_min");
202 lua_pushnumber(L, (*s_cur)->min);
205 lua_pushstring(L, "measure_max");
206 lua_pushnumber(L, (*s_cur)->max);
209 lua_pushstring(L, "id");
210 lua_pushstring(L, (*s_cur)->id);
219 lua_setglobal(L, "sensors");
221 lua_fpath = malloc(strlen(www_dir) + strlen(url) + 1);
222 strcpy(lua_fpath, www_dir);
223 strcat(lua_fpath, url);
225 if (!luaL_loadfile(L, lua_fpath) && !lua_pcall(L, 0, 1, 0))
226 page = strdup(lua_tostring(L, -1));
235 static int cbk_http_request(void *cls,
236 struct MHD_Connection *connection,
240 const char *upload_data,
241 size_t *upload_data_size, void **ptr)
243 struct psensor **sensors = cls;
245 struct MHD_Response *response;
248 unsigned int resp_code;
251 if (strcmp(method, "GET"))
252 return MHD_NO; /* unexpected method */
254 if (&dummy != *ptr) {
255 /* The first time only the headers are valid, do not
256 respond in the first round... */
261 if (*upload_data_size)
262 return MHD_NO; /* upload data in a GET!? */
264 *ptr = NULL; /* clear context pointer */
266 nurl = url_normalize(url);
268 pthread_mutex_lock(&mutex);
270 if (!strcmp(nurl, URL_BASE_API_1_0_SENSORS)) {
271 page = sensors_to_json_string(sensors);
273 } else if (!strncmp(nurl, URL_BASE_API_1_0_SENSORS,
274 strlen(URL_BASE_API_1_0_SENSORS))
275 && nurl[strlen(URL_BASE_API_1_0_SENSORS)] == '/') {
277 char *sid = nurl + strlen(URL_BASE_API_1_0_SENSORS) + 1;
278 struct psensor *s = psensor_list_get_by_id(sensors, sid);
281 page = sensor_to_json_string(s);
284 page = lua_to_html_page(sensors, nurl);
288 resp_code = MHD_HTTP_OK;
290 page = strdup(PAGE_NOT_FOUND);
291 resp_code = MHD_HTTP_NOT_FOUND;
294 pthread_mutex_unlock(&mutex);
296 response = MHD_create_response_from_data(strlen(page),
297 (void *)page, MHD_YES, MHD_NO);
299 ret = MHD_queue_response(connection, resp_code, response);
300 MHD_destroy_response(response);
307 int main(int argc, char *argv[])
310 float last_total = 0;
311 struct MHD_Daemon *d;
312 struct psensor **sensors;
313 int port = DEFAULT_PORT;
316 int c, option_index = 0;
318 c = getopt_long(argc, argv, "vhpw:", long_options,
331 www_dir = strdup(optarg);
341 printf("%s\n%s\n\n%s\n\n%s\n",
342 PSENSOR_SERVER_USAGE,
343 PSENSOR_SERVER_DESCRIPTION,
344 PSENSOR_SERVER_OPTIONS, PSENSOR_SERVER_CONTACT);
348 printf("psensor-server %s\n", VERSION);
349 printf("%s\n", PSENSOR_SERVER_COPYRIGHT);
361 if (optind != argc) {
362 fprintf(stderr, "Invalid usage.\n");
366 if (!lmsensor_init()) {
367 fprintf(stderr, "failed to init lm-sensors\n");
371 sensors = get_all_sensors(1);
373 if (!sensors || !*sensors) {
374 fprintf(stderr, "no sensors detected\n");
378 d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION,
380 NULL, NULL, &cbk_http_request, sensors,
383 fprintf(stderr, "Fail to create web server\n");
387 printf("Web server started on port: %d\n", port);
388 printf("Psensor URL: http://localhost:%d\n", port);
391 unsigned long int used = 0;
392 unsigned long int dt;
394 pthread_mutex_lock(&mutex);
398 cpu = malloc(sizeof(glibtop_cpu));
400 glibtop_get_cpu(cpu);
402 used = cpu->user + cpu->nice + cpu->sys;
404 dt = cpu->total - last_total;
407 cpu_rate = (used - last_used) / dt;
410 last_total = cpu->total;
412 psensor_list_update_measures(sensors);
415 pthread_mutex_unlock(&mutex);