fixed memory leak
Costa Tsaousis (ktsaou) committed
Apr 7, 2014 at 17:33 UTC
6275b95abaffd304ec75ff5d8e8480185e824d8c
1 file changed
+114
-99
netdata.c
+114
-99
@@ -648,87 +648,6 @@ int rrd_stats_dimension_set(RRD_STATS *st, const char *id, void *data)
648
return 0;
649
}
650
651
-#define GROUP_AVERAGE 0
652
-#define GROUP_MAX 1
653
-
654
-size_t rrd_stats_one_json(RRD_STATS *st, char *options, char *buffer, size_t len)
655
-{
656
- size_t i = 0;
657
- if(i + 200 > len) return(0);
658
-
659
- i += sprintf(&buffer[i], "\t\t{\n");
660
- i += sprintf(&buffer[i], "\t\t\t\"id\" : \"%s\",\n", st->id);
661
- i += sprintf(&buffer[i], "\t\t\t\"name\" : \"%s\",\n", st->name);
662
- i += sprintf(&buffer[i], "\t\t\t\"type\" : \"%s\",\n", st->type);
663
- i += sprintf(&buffer[i], "\t\t\t\"title\" : \"%s %s\",\n", st->title, st->name);
664
- i += sprintf(&buffer[i], "\t\t\t\"usertitle\" : \"%s %s (%s)\",\n", st->title, st->usertitle, st->id);
665
- i += sprintf(&buffer[i], "\t\t\t\"userpriority\" : \"%s\",\n", st->userpriority);
666
- i += sprintf(&buffer[i], "\t\t\t\"envtitle\" : \"%s\",\n", st->envtitle);
667
- i += sprintf(&buffer[i], "\t\t\t\"envpriority\" : \"%s\",\n", st->envpriority);
668
- i += sprintf(&buffer[i], "\t\t\t\"hostname\" : \"%s\",\n", st->hostname);
669
- i += sprintf(&buffer[i], "\t\t\t\"vtitle\" : \"%s\",\n", st->vtitle);
670
- i += sprintf(&buffer[i], "\t\t\t\"url\" : \"/data/%s/%s\",\n", st->name, options?options:"");
671
- i += sprintf(&buffer[i], "\t\t\t\"entries\" : %ld,\n", st->entries);
672
- i += sprintf(&buffer[i], "\t\t\t\"current\" : %ld,\n", st->current_entry);
673
- i += sprintf(&buffer[i], "\t\t\t\"update_every\" : %d,\n", update_every);
674
- i += sprintf(&buffer[i], "\t\t\t\"last_updated\" : %lu,\n", st->last_updated);
675
- i += sprintf(&buffer[i], "\t\t\t\"last_updated_secs_ago\" : %lu\n", time(NULL) - st->last_updated);
676
- i += sprintf(&buffer[i], "\t\t}");
677
-
678
- return(i);
679
-}
680
-
681
-#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
682
-#define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
683
-
684
-size_t rrd_stats_graph_json(RRD_STATS *st, char * options, char *buffer, size_t len)
685
-{
686
- size_t i = 0;
687
- i += sprintf(&buffer[i], RRD_GRAPH_JSON_HEADER);
688
- i += rrd_stats_one_json(st, options, &buffer[i], len - i);
689
- i += sprintf(&buffer[i], RRD_GRAPH_JSON_FOOTER);
690
- return(i);
691
-}
692
-
693
-size_t rrd_stats_all_json(char *buffer, size_t len)
694
-{
695
- size_t i = 0, c;
696
- RRD_STATS *st;
697
-
698
- i += sprintf(&buffer[i], RRD_GRAPH_JSON_HEADER);
699
-
700
- for(st = root, c = 0; st ; st = st->next, c++) {
701
- if(c) i += sprintf(&buffer[i], "%s", ",\n");
702
- i += rrd_stats_one_json(st, NULL, &buffer[i], len - i);
703
- }
704
-
705
- i += sprintf(&buffer[i], RRD_GRAPH_JSON_FOOTER);
706
- return(i);
707
-}
708
-
709
-long long rrd_stats_dimension_get(RRD_DIMENSION *rd, size_t position)
710
-{
711
- if(rd->bytes == sizeof(long long)) {
712
- long long *dimension = rd->values;
713
- return(dimension[position]);
714
- }
715
- else if(rd->bytes == sizeof(long)) {
716
- long *dimension = rd->values;
717
- return(dimension[position]);
718
- }
719
- else if(rd->bytes == sizeof(int)) {
720
- int *dimension = rd->values;
721
- return(dimension[position]);
722
- }
723
- else if(rd->bytes == sizeof(char)) {
724
- char *dimension = rd->values;
725
- return(dimension[position]);
726
- }
727
- else fatal("Cannot produce JSON for size %d bytes dimension.", rd->bytes);
728
-
729
- return(0);
730
-}
731
-
651
652
// ----------------------------------------------------------------------------
653
// web buffer
@@ -783,7 +702,7 @@ void web_buffer_increase(struct web_buffer *b, size_t free_size_required)
702
703
debug(D_WEB_BUFFER, "Increasing data buffer from size %d to %d.", b->size, b->size + increase);
704
786
- b->buffer = realloc(b->buffer, b->size + free_size_required - left);
705
+ b->buffer = realloc(b->buffer, b->size + increase);
706
if(!b->buffer) fatal("Failed to increase data buffer from size %d to %d.", b->size, b->size + increase);
707
708
b->size += increase;
@@ -796,6 +715,8 @@ struct web_client {
715
unsigned long long id;
716
char client_ip[101];
717
718
+ struct timeval tv_in, tv_ready;
719
+
720
int mode;
721
int keepalive;
722
@@ -896,7 +817,86 @@ struct web_client *web_client_free(struct web_client *w)
817
return(n);
818
}
819
899
-size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group_count, int group_method)
820
+#define GROUP_AVERAGE 0
821
+#define GROUP_MAX 1
822
+
823
+void rrd_stats_one_json(RRD_STATS *st, char *options, struct web_buffer *wb)
824
+{
825
+ web_buffer_increase(wb, 8192);
826
+
827
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t{\n");
828
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"id\" : \"%s\",\n", st->id);
829
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"name\" : \"%s\",\n", st->name);
830
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"type\" : \"%s\",\n", st->type);
831
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"title\" : \"%s %s\",\n", st->title, st->name);
832
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"usertitle\" : \"%s %s (%s)\",\n", st->title, st->usertitle, st->id);
833
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"userpriority\" : \"%s\",\n", st->userpriority);
834
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"envtitle\" : \"%s\",\n", st->envtitle);
835
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"envpriority\" : \"%s\",\n", st->envpriority);
836
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"hostname\" : \"%s\",\n", st->hostname);
837
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"vtitle\" : \"%s\",\n", st->vtitle);
838
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"url\" : \"/data/%s/%s\",\n", st->name, options?options:"");
839
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"entries\" : %ld,\n", st->entries);
840
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"current\" : %ld,\n", st->current_entry);
841
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"update_every\" : %d,\n", update_every);
842
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_updated\" : %lu,\n", st->last_updated);
843
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t\t\"last_updated_secs_ago\" : %lu\n", time(NULL) - st->last_updated);
844
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], "\t\t}");
845
+}
846
+
847
+#define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
848
+#define RRD_GRAPH_JSON_FOOTER "\n\t]\n}\n"
849
+
850
+void rrd_stats_graph_json(RRD_STATS *st, char *options, struct web_buffer *wb)
851
+{
852
+ web_buffer_increase(wb, 4096);
853
+
854
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], RRD_GRAPH_JSON_HEADER);
855
+ rrd_stats_one_json(st, options, wb);
856
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], RRD_GRAPH_JSON_FOOTER);
857
+}
858
+
859
+void rrd_stats_all_json(struct web_buffer *wb)
860
+{
861
+ web_buffer_increase(wb, 4096);
862
+
863
+ size_t c;
864
+ RRD_STATS *st;
865
+
866
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], RRD_GRAPH_JSON_HEADER);
867
+
868
+ for(st = root, c = 0; st ; st = st->next, c++) {
869
+ if(c) wb->bytes += sprintf(&wb->buffer[wb->bytes], "%s", ",\n");
870
+ rrd_stats_one_json(st, NULL, wb);
871
+ }
872
+
873
+ wb->bytes += sprintf(&wb->buffer[wb->bytes], RRD_GRAPH_JSON_FOOTER);
874
+}
875
+
876
+long long rrd_stats_dimension_get(RRD_DIMENSION *rd, size_t position)
877
+{
878
+ if(rd->bytes == sizeof(long long)) {
879
+ long long *dimension = rd->values;
880
+ return(dimension[position]);
881
+ }
882
+ else if(rd->bytes == sizeof(long)) {
883
+ long *dimension = rd->values;
884
+ return(dimension[position]);
885
+ }
886
+ else if(rd->bytes == sizeof(int)) {
887
+ int *dimension = rd->values;
888
+ return(dimension[position]);
889
+ }
890
+ else if(rd->bytes == sizeof(char)) {
891
+ char *dimension = rd->values;
892
+ return(dimension[position]);
893
+ }
894
+ else fatal("Cannot produce JSON for size %d bytes dimension.", rd->bytes);
895
+
896
+ return(0);
897
+}
898
+
899
+void rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_show, size_t group_count, int group_method)
900
{
901
char *b = wb->buffer;
902
@@ -907,7 +907,6 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
907
if(group_count <= 0) group_count = 1;
908
if(group_count > st->entries / 20) group_count = st->entries / 20;
909
910
- size_t i = 0; // the bytes of JSON output we have generated so far
910
size_t printed = 0; // the lines of JSON data we have generated so far
911
912
size_t current_entry = st->current_entry;
@@ -932,7 +931,8 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
931
932
if(!dimensions) {
933
pthread_mutex_unlock(&st->mutex);
935
- return (wb->bytes = sprintf(b, "No dimensions yet."));
934
+ wb->bytes = sprintf(b, "No dimensions yet.");
935
+ return;
936
}
937
938
// temporary storage to keep track of group values and counts
@@ -941,14 +941,14 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
941
for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
942
group_values[c] = group_counts[c] = 0;
943
944
- i += sprintf(&b[i], "{\n \"cols\":\n [\n");
945
- i += sprintf(&b[i], " {\"id\":\"\",\"label\":\"time\",\"pattern\":\"\",\"type\":\"datetime\"}");
944
+ wb->bytes += sprintf(&b[wb->bytes], "{\n \"cols\":\n [\n");
945
+ wb->bytes += sprintf(&b[wb->bytes], " {\"id\":\"\",\"label\":\"time\",\"pattern\":\"\",\"type\":\"datetime\"}");
946
947
for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
948
if(!rd->hidden)
949
- i += sprintf(&b[i], ",\n {\"id\":\"\",\"label\":\"%s\",\"pattern\":\"\",\"type\":\"number\"}", rd->name);
949
+ wb->bytes += sprintf(&b[wb->bytes], ",\n {\"id\":\"\",\"label\":\"%s\",\"pattern\":\"\",\"type\":\"number\"}", rd->name);
950
951
- i += sprintf(&b[i], " ],\n \"rows\":\n [\n");
951
+ wb->bytes += sprintf(&b[wb->bytes], " ],\n \"rows\":\n [\n");
952
953
// to allow grouping on the same values, we need a pad
954
pad = current_entry % group_count;
@@ -974,7 +974,7 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
974
if(!st->times[lt].tv_sec) continue;
975
976
// check if we may exceed the buffer provided
977
- web_buffer_increase(wb, 4096);
977
+ web_buffer_increase(wb, 1024 + (50 * dimensions));
978
979
// prefer the most recent last entries
980
if(((count-pad) / group_count) > entries_to_show) continue;
@@ -995,7 +995,7 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
995
sprintf(dtm, "\"Date(%d, %d, %d, %d, %d, %d, %d)\"", tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(st->times[t].tv_usec / 1000)); // datetime
996
// strftime(dtm, 200, "\"Date(%Y, %m, %d, %H, %M, %S)\"", tm); // datetime
997
// strftime(dtm, 200, "[%H, %M, %S, 0]", tm); // timeofday
998
- i += sprintf(&b[i], "%s {\"c\":[{\"v\":%s}", printed?"]},\n":"", dtm);
998
+ wb->bytes += sprintf(&b[wb->bytes], "%s {\"c\":[{\"v\":%s}", printed?"]},\n":"", dtm);
999
1000
printed++;
1001
}
@@ -1048,18 +1048,17 @@ size_t rrd_stats_json(RRD_STATS *st, struct web_buffer *wb, size_t entries_to_sh
1048
1049
if(((count-pad) % group_count) == 0) {
1050
if(!rd->hidden)
1051
- i += sprintf(&b[i], ",{\"v\":%0.1Lf}", group_values[c]);
1052
- //i += sprintf(&b[i], ",{\"v\":%lld}", group_values[c]);
1051
+ wb->bytes += sprintf(&b[wb->bytes], ",{\"v\":%0.1Lf}", group_values[c]);
1052
+ //wb->bytes += sprintf(&b[wb->bytes], ",{\"v\":%lld}", group_values[c]);
1053
1054
group_values[c] = group_counts[c] = 0;
1055
}
1056
}
1057
}
1058
- if(printed) i += sprintf(&b[i], "]}");
1059
- i += sprintf(&b[i], "\n ]\n}\n");
1058
+ if(printed) wb->bytes += sprintf(&b[wb->bytes], "]}");
1059
+ wb->bytes += sprintf(&b[wb->bytes], "\n ]\n}\n");
1060
1061
pthread_mutex_unlock(&st->mutex);
1062
- return(wb->bytes = i);
1062
}
1063
1064
int mysendfile(struct web_client *w, char *filename)
@@ -1248,6 +1247,7 @@ void web_client_process(struct web_client *w)
1247
1248
// check if we have an empty line (end of HTTP header)
1249
if(strstr(w->data->buffer, "\r\n\r\n")) {
1250
+ gettimeofday(&w->tv_in, NULL);
1251
debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->data->bytes, w->data->buffer);
1252
1253
// check if the client requested keep-alive HTTP
@@ -1293,6 +1293,7 @@ void web_client_process(struct web_client *w)
1293
if(!st) {
1294
// we don't have it
1295
// try to send a file with that name
1296
+ w->data->bytes = 0;
1297
code = mysendfile(w, tok);
1298
}
1299
else {
@@ -1330,7 +1331,8 @@ void web_client_process(struct web_client *w)
1331
1332
code = 200;
1333
w->data->contenttype = CT_APPLICATION_JSON;
1333
- w->data->bytes = rrd_stats_json(st, w->data, lines, group_count, group_method);
1334
+ w->data->bytes = 0;
1335
+ rrd_stats_json(st, w->data, lines, group_count, group_method);
1336
}
1337
}
1338
else if(strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
@@ -1345,6 +1347,7 @@ void web_client_process(struct web_client *w)
1347
if(!st) {
1348
// we don't have it
1349
// try to send a file with that name
1350
+ w->data->bytes = 0;
1351
code = mysendfile(w, tok);
1352
}
1353
else {
@@ -1352,7 +1355,8 @@ void web_client_process(struct web_client *w)
1355
syslog(LOG_NOTICE, "%llu: Sending '%s' graph to client %s.", w->id, st->name, w->client_ip);
1356
debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
1357
w->data->contenttype = CT_APPLICATION_JSON;
1355
- w->data->bytes = rrd_stats_graph_json(st, url, w->data->buffer, w->data->size);
1358
+ w->data->bytes = 0;
1359
+ rrd_stats_graph_json(st, url, w->data);
1360
}
1361
}
1362
else if(strcmp(tok, "mirror") == 0) {
@@ -1396,21 +1400,25 @@ void web_client_process(struct web_client *w)
1400
syslog(LOG_NOTICE, "%llu: Sending list with all graphs in JSON to client %s.", w->id, w->client_ip);
1401
1402
w->data->contenttype = CT_APPLICATION_JSON;
1399
- w->data->bytes = rrd_stats_all_json(w->data->buffer, w->data->size);
1403
+ w->data->bytes = 0;
1404
+ rrd_stats_all_json(w->data);
1405
}
1406
else if(strcmp(tok, WEB_PATH_FILE) == 0) { // "file"
1407
tok = mystrsep(&url, "/?&");
1408
if(tok && *tok) code = mysendfile(w, tok);
1409
else {
1410
code = 400;
1411
+ w->data->bytes = 0;
1412
strcpy(w->data->buffer, "You have to give a filename to get.\r\n");
1413
w->data->bytes = strlen(w->data->buffer);
1414
}
1415
}
1416
else if(!tok[0]) {
1417
+ w->data->bytes = 0;
1418
code = mysendfile(w, "index.html");
1419
}
1420
else {
1421
+ w->data->bytes = 0;
1422
code = mysendfile(w, tok);
1423
}
1424
}
@@ -1418,6 +1426,7 @@ void web_client_process(struct web_client *w)
1426
if(buf) debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, buf);
1427
1428
code = 500;
1429
+ w->data->bytes = 0;
1430
strcpy(w->data->buffer, "I don't understand you...\r\n");
1431
w->data->bytes = strlen(w->data->buffer);
1432
}
@@ -1426,6 +1435,7 @@ void web_client_process(struct web_client *w)
1435
debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big.", w->id);
1436
1437
code = 400;
1438
+ w->data->bytes = 0;
1439
strcpy(w->data->buffer, "Received request is too big.\r\n");
1440
w->data->bytes = strlen(w->data->buffer);
1441
}
@@ -1435,6 +1445,11 @@ void web_client_process(struct web_client *w)
1445
return;
1446
}
1447
1448
+ if(w->data->bytes > w->data->size) {
1449
+ error("%llu: memory overflow encountered (size is %ld, written %ld).", w->data->size, w->data->bytes);
1450
+ }
1451
+
1452
+ gettimeofday(&w->tv_ready, NULL);
1453
w->data->date = time(NULL);
1454
w->data->sent = 0;
1455