Changeset 5622

Use a dynamic string in cdr_csv rather than a local implementation

Committed by:  mjagdis
Date:  Feb 09 2010 * 00:24 (6 months ago)

Affected files:

callweaver/trunk/cdr/cdr_csv.c (unified diff)

r5562r5622
11 /*
22 * CallWeaver -- An open source telephony toolkit.
33 *
4 * Copyright (C) 2009, Eris Associates Limited, UK
4 * Copyright (C) 2009 - 2010, Eris Associates Limited, UK
55 * Copyright (C) 1999 - 2005, Digium, Inc.
66 *
77 * Mike Jagdis <mjagdis@eris-associates.co.uk>
------
6666 static char csvacct_path[CW_CONFIG_MAX_PATH];
6767 static int csvacct_offset;
6868
69 static char *gbuf;
70 static size_t gbufsize;
71 #define atleast(n) ((n + 255) / 256)
7269
73
74 static int expand(size_t n)
70 static void append_string(struct cw_dynstr **ds_p, const char *s)
7571 {
76 char *nbuf;
72 cw_dynstr_printf(ds_p, "\"");
7773
78 if ((nbuf = realloc(gbuf, gbufsize + n))) {
79 gbuf = nbuf;
80 gbufsize += n;
81 return 0;
74 while (*s) {
75 int n = strcspn(s, "\"");
76 cw_dynstr_printf(ds_p, "%.*s", n, s);
77 if (!s[n])
78 break;
79 cw_dynstr_printf(ds_p, "\"\"");
80 s += n + 1;
8281 }
8382
84 return -1;
83 cw_dynstr_printf(ds_p, "\",");
8584 }
8685
8786
88 static int append_string(size_t *pos, char *buf, size_t bufsize, const char *s)
87 static void append_times(struct cw_dynstr **ds_p, const struct cw_cdr *cdr)
8988 {
90 int res = -1;
91
92 if (bufsize - *pos < 3 && expand(atleast(3)))
93 goto out;
94
95 buf[(*pos)++] = '\"';
96
97 for (; *s; s++) {
98 if (bufsize - *pos < 2 + 2 && expand(atleast(2)))
99 goto out;
100 if ((buf[(*pos)++] = *s) == '\"')
101 buf[(*pos)++] = '\"';
102 }
103
104 buf[*pos + 0] = '\"';
105 buf[*pos + 1] = ',';
106 *pos += 2;
107
108 res = 0;
109
110 out:
111 return res;
89 cw_dynstr_printf(ds_p, "%d,%d,", cdr->duration, cdr->billsec);
11290 }
11391
11492
115 static int append_times(size_t *pos, char *buf, size_t bufsize, const struct cw_cdr *cdr)
93 static void append_date(struct cw_dynstr **ds_p, const struct timeval tv)
11694 {
117 int res = -1;
118 int n;
119
120 for (;;) {
121 n = snprintf(buf + *pos, bufsize - *pos, "%d,%d,", cdr->duration, cdr->billsec);
122 if (bufsize - *pos >= n + 1)
123 break;
124 if (expand(atleast(n + 1)))
125 goto out;
126 }
127
128 *pos += n;
129 res = 0;
130
131 out:
132 return res;
133 }
134
135
136 static int append_date(size_t *pos, char *buf, size_t bufsize, const struct timeval tv)
137 {
13895 struct tm tm;
139 int res = -1;
14096
14197 if (!cw_tvzero(tv)) {
142 if (bufsize - *pos < MAX_DATE_LEN + 1 && expand(atleast(MAX_DATE_LEN + 1)))
143 goto out;
98 cw_dynstr_need(ds_p, MAX_DATE_LEN + sizeof(",") - 1);
14499 localtime_r(&tv.tv_sec, &tm);
145 *pos += strftime(buf + *pos, bufsize - *pos, DATE_FORMAT ",", &tm);
100 (*ds_p)->used += strftime((*ds_p)->data + (*ds_p)->used, (*ds_p)->size - (*ds_p)->used, DATE_FORMAT ",", &tm);
146101 }
147
148 res = 0;
149
150 out:
151 return res;
152102 }
153103
154104
155 static char *build_csv_record(size_t *pos, const struct cw_cdr *cdr)
105 static void build_csv_record(struct cw_dynstr **ds_p, const struct cw_cdr *cdr)
156106 {
157 *pos = 0;
158
159 if (!append_string(pos, gbuf, gbufsize, cdr->accountcode)
160 && !append_string(pos, gbuf, gbufsize, cdr->src)
161 && !append_string(pos, gbuf, gbufsize, cdr->dst)
162 && !append_string(pos, gbuf, gbufsize, cdr->dcontext)
163 && !append_string(pos, gbuf, gbufsize, cdr->clid)
164 && !append_string(pos, gbuf, gbufsize, cdr->channel)
165 && !append_string(pos, gbuf, gbufsize, cdr->dstchannel)
166 && !append_string(pos, gbuf, gbufsize, cdr->lastapp)
167 && !append_string(pos, gbuf, gbufsize, cdr->lastdata)
168 && !append_date(pos, gbuf, gbufsize, cdr->start)
169 && !append_date(pos, gbuf, gbufsize, cdr->answer)
170 && !append_date(pos, gbuf, gbufsize, cdr->end)
171 && !append_times(pos, gbuf, gbufsize, cdr)
172 && !append_string(pos, gbuf, gbufsize, cw_cdr_disp2str(cdr->disposition))
173 && !append_string(pos, gbuf, gbufsize, cw_cdr_flags2str(cdr->amaflags))
107 append_string(ds_p, cdr->accountcode);
108 append_string(ds_p, cdr->src);
109 append_string(ds_p, cdr->dst);
110 append_string(ds_p, cdr->dcontext);
111 append_string(ds_p, cdr->clid);
112 append_string(ds_p, cdr->channel);
113 append_string(ds_p, cdr->dstchannel);
114 append_string(ds_p, cdr->lastapp);
115 append_string(ds_p, cdr->lastdata);
116 append_date(ds_p, cdr->start);
117 append_date(ds_p, cdr->answer);
118 append_date(ds_p, cdr->end);
119 append_times(ds_p, cdr);
120 append_string(ds_p, cw_cdr_disp2str(cdr->disposition));
121 append_string(ds_p, cw_cdr_flags2str(cdr->amaflags));
174122 #ifdef CSV_LOGUNIQUEID
175 && !append_string(pos, gbuf, gbufsize, cdr->uniqueid)
123 append_string(ds_p, cdr->uniqueid);
176124 #endif
177125 #ifdef CSV_LOGUSERFIELD
178 && !append_string(pos, gbuf, gbufsize, cdr->userfield)
126 append_string(ds_p, cdr->userfield);
179127 #endif
180 ) {
181 /* Trim off trailing comma */
182 gbuf[*pos - 1] = '\n';
183 return gbuf;
184 }
185128
186 return NULL;
129 /* Replace trailing comma with a newline */
130 if ((*ds_p) && !(*ds_p)->error)
131 (*ds_p)->data[(*ds_p)->used - 1] = '\n';
187132 }
188133
189134
------
217162 static int csv_log(struct cw_cdr *batch)
218163 {
219164 struct cw_cdr *cdrset, *cdr;
220 char *buf;
221 size_t len;
165 struct cw_dynstr *ds = NULL;
222166
223167 pthread_mutex_lock(&csv_lock);
224168
------
227171 batch = batch->batch_next;
228172
229173 while ((cdr = cdrset)) {
230 cdrset = cdrset->next;
174 build_csv_record(&ds, cdr);
231175
232 if ((buf = build_csv_record(&len, cdr))) {
233 fwrite(buf, len, 1, csvmaster_fd);
176 if (ds && !ds->error) {
177 cdrset = cdrset->next;
234178
179 fwrite(ds->data, 1, ds->used, csvmaster_fd);
180
235181 if (!cw_strlen_zero(cdr->accountcode)) {
236182 static char badacct = 0;
237183 static char toolong = 0;
------
241187 if (!strchr(cdr->accountcode, '/') && (cdr->accountcode[0] != '.' || cdr->accountcode[1] != '.')) {
242188 if (snprintf(csvacct_path + csvacct_offset, sizeof(csvacct_path) - csvacct_offset, "%s.csv", cdr->accountcode) < sizeof(csvacct_path) - csvacct_offset) {
243189 if (!(err = ((d = open_cloexec(csvacct_path, O_WRONLY|O_APPEND|O_CREAT, 0666)) < 0))) {
244 err = (write(d, buf, len) != len);
190 err = (write(d, ds->data, ds->used) != ds->used);
245191 err |= fsync(d);
246192 err |= close(d);
247193 }
------
258204 badacct = 1;
259205 }
260206 }
207
208 cw_dynstr_reset(&ds);
209 } else {
210 if (ds)
211 cw_dynstr_free(&ds);
212 cw_log(CW_LOG_ERROR, "Out of memory!\n");
213 sleep(1);
261214 }
262215 }
263216 }
------
268221
269222 pthread_mutex_unlock(&csv_lock);
270223
224 if (ds)
225 cw_dynstr_free(&ds);
226
271227 return 0;
272228 }
273229
------
295251
296252 static int load_module(void)
297253 {
298 if (!(gbuf = malloc(1024))) {
299 cw_log(CW_LOG_ERROR, "Out of memory!\n");
300 return -1;
301 }
302 gbufsize = 1024;
303
304254 snprintf(csvmaster_path, sizeof(csvmaster_path), "%s/%s/%s", cw_config_CW_LOG_DIR, CSV_LOG_DIR, CSV_MASTER);
305255 csvacct_offset = snprintf(csvacct_path, sizeof(csvacct_path), "%s/%s/", cw_config_CW_LOG_DIR, CSV_LOG_DIR);
306256