src/rrd_client.c: Remove useless `FILE *sh;'.
[rrdtool.git] / src / rrd_client.c
1 /**
2  * RRDTool - src/rrd_client.c
3  * Copyright (C) 2008 Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  **/
21
22 #include "rrd.h"
23 #include "rrd_client.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <pthread.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <netdb.h>
34
35 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
36 static int sd = -1;
37
38 static ssize_t sread (void *buffer_void, size_t buffer_size) /* {{{ */
39 {
40   char    *buffer;
41   size_t   buffer_used;
42   size_t   buffer_free;
43   ssize_t  status;
44
45   buffer       = (char *) buffer_void;
46   buffer_used  = 0;
47   buffer_free  = buffer_size;
48
49   while (buffer_free > 0)
50   {
51     status = read (sd, buffer + buffer_used, buffer_free);
52     if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
53       continue;
54
55     if (status < 0)
56       return (-1);
57
58     if (status == 0)
59     {
60       close (sd);
61       sd = -1;
62       errno = EPROTO;
63       return (-1);
64     }
65
66     assert ((0 > status) || (buffer_free >= (size_t) status));
67
68     buffer_free = buffer_free - status;
69     buffer_used = buffer_used + status;
70
71     if (buffer[buffer_used - 1] == '\n')
72       break;
73   }
74
75   if (buffer[buffer_used - 1] != '\n')
76   {
77     errno = ENOBUFS;
78     return (-1);
79   }
80
81   buffer[buffer_used - 1] = 0;
82   return (buffer_used);
83 } /* }}} ssize_t sread */
84
85 static ssize_t swrite (const void *buf, size_t count) /* {{{ */
86 {
87   const char *ptr;
88   size_t      nleft;
89   ssize_t     status;
90
91   ptr   = (const char *) buf;
92   nleft = count;
93
94   while (nleft > 0)
95   {
96     status = write (sd, (const void *) ptr, nleft);
97
98     if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
99       continue;
100
101     if (status < 0)
102       return (status);
103
104     nleft = nleft - status;
105     ptr   = ptr   + status;
106   }
107
108   return (0);
109 } /* }}} ssize_t swrite */
110
111 static int buffer_add_string (const char *str, /* {{{ */
112     char **buffer_ret, size_t *buffer_size_ret)
113 {
114   char *buffer;
115   size_t buffer_size;
116   size_t buffer_pos;
117   size_t i;
118   int status;
119
120   buffer = *buffer_ret;
121   buffer_size = *buffer_size_ret;
122   buffer_pos = 0;
123
124   i = 0;
125   status = -1;
126   while (buffer_pos < buffer_size)
127   {
128     if (str[i] == 0)
129     {
130       buffer[buffer_pos] = ' ';
131       buffer_pos++;
132       status = 0;
133       break;
134     }
135     else if ((str[i] == ' ') || (str[i] == '\\'))
136     {
137       if (buffer_pos >= (buffer_size - 1))
138         break;
139       buffer[buffer_pos] = '\\';
140       buffer_pos++;
141       buffer[buffer_pos] = str[i];
142       buffer_pos++;
143     }
144     else
145     {
146       buffer[buffer_pos] = str[i];
147       buffer_pos++;
148     }
149     i++;
150   } /* while (buffer_pos < buffer_size) */
151
152   if (status != 0)
153     return (-1);
154
155   *buffer_ret = buffer + buffer_pos;
156   *buffer_size_ret = buffer_size - buffer_pos;
157
158   return (0);
159 } /* }}} int buffer_add_string */
160
161 static int buffer_add_value (const char *value, /* {{{ */
162     char **buffer_ret, size_t *buffer_size_ret)
163 {
164   char temp[4096];
165
166   if (strncmp (value, "N:", 2) == 0)
167     snprintf (temp, sizeof (temp), "%lu:%s",
168         (unsigned long) time (NULL), value + 2);
169   else
170     strncpy (temp, value, sizeof (temp));
171   temp[sizeof (temp) - 1] = 0;
172
173   return (buffer_add_string (temp, buffer_ret, buffer_size_ret));
174 } /* }}} int buffer_add_value */
175
176 static int rrdc_connect_unix (const char *path) /* {{{ */
177 {
178   struct sockaddr_un sa;
179   int status;
180
181   if (path == NULL)
182     path = RRDD_SOCK_PATH;
183
184   pthread_mutex_lock (&lock);
185
186   if (sd >= 0)
187   {
188     pthread_mutex_unlock (&lock);
189     return (0);
190   }
191
192   sd = socket (PF_UNIX, SOCK_STREAM, /* protocol = */ 0);
193   if (sd < 0)
194   {
195     status = errno;
196     pthread_mutex_unlock (&lock);
197     return (status);
198   }
199
200   memset (&sa, 0, sizeof (sa));
201   sa.sun_family = AF_UNIX;
202   strncpy (sa.sun_path, path, sizeof (sa.sun_path) - 1);
203
204   status = connect (sd, (struct sockaddr *) &sa, sizeof (sa));
205   if (status != 0)
206   {
207     status = errno;
208     pthread_mutex_unlock (&lock);
209     return (status);
210   }
211
212   pthread_mutex_unlock (&lock);
213
214   return (0);
215 } /* }}} int rrdc_connect_unix */
216
217 int rrdc_connect (const char *addr) /* {{{ */
218 {
219   struct addrinfo ai_hints;
220   struct addrinfo *ai_res;
221   struct addrinfo *ai_ptr;
222   int status;
223
224   if (addr == NULL)
225     addr = RRDD_SOCK_PATH;
226
227   if (strncmp ("unix:", addr, strlen ("unix:")) == 0)
228     return (rrdc_connect_unix (addr + strlen ("unix:")));
229   else if (addr[0] == '/')
230     return (rrdc_connect_unix (addr));
231
232   pthread_mutex_lock (&lock);
233
234   if (sd >= 0)
235   {
236     pthread_mutex_unlock (&lock);
237     return (0);
238   }
239
240   memset (&ai_hints, 0, sizeof (ai_hints));
241   ai_hints.ai_flags = 0;
242 #ifdef AI_ADDRCONFIG
243   ai_hints.ai_flags |= AI_ADDRCONFIG;
244 #endif
245   ai_hints.ai_family = AF_UNSPEC;
246   ai_hints.ai_socktype = SOCK_STREAM;
247
248   ai_res = NULL;
249   status = getaddrinfo (addr, DEFAULT_PORT, &ai_hints, &ai_res);
250   if (status != 0)
251   {
252     pthread_mutex_unlock (&lock);
253     return (status);
254   }
255
256   for (ai_ptr = ai_res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
257   {
258     sd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
259     if (sd < 0)
260     {
261       status = errno;
262       sd = -1;
263       continue;
264     }
265
266     status = connect (sd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
267     if (status != 0)
268     {
269       status = errno;
270       close (sd);
271       sd = -1;
272       continue;
273     }
274
275     assert (status == 0);
276     break;
277   } /* for (ai_ptr) */
278   pthread_mutex_unlock (&lock);
279
280   return (status);
281 } /* }}} int rrdc_connect */
282
283 int rrdc_disconnect (void) /* {{{ */
284 {
285   pthread_mutex_lock (&lock);
286
287   if (sd < 0)
288   {
289     pthread_mutex_unlock (&lock);
290     return (0);
291   }
292
293   close (sd);
294   sd = -1;
295
296   pthread_mutex_unlock (&lock);
297
298   return (0);
299 } /* }}} int rrdc_disconnect */
300
301 int rrdc_update (const char *filename, int values_num, /* {{{ */
302                 const char * const *values)
303 {
304   char buffer[4096];
305   char *buffer_ptr;
306   size_t buffer_free;
307   size_t buffer_size;
308   int status;
309   int i;
310
311   memset (buffer, 0, sizeof (buffer));
312   buffer_ptr = &buffer[0];
313   buffer_free = sizeof (buffer);
314
315   status = buffer_add_string ("update", &buffer_ptr, &buffer_free);
316   if (status != 0)
317     return (ENOBUFS);
318
319   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
320   if (status != 0)
321     return (ENOBUFS);
322
323   for (i = 0; i < values_num; i++)
324   {
325     status = buffer_add_value (values[i], &buffer_ptr, &buffer_free);
326     if (status != 0)
327       return (ENOBUFS);
328   }
329
330   assert (buffer_free < sizeof (buffer));
331   buffer_size = sizeof (buffer) - buffer_free;
332   assert (buffer[buffer_size - 1] == ' ');
333   buffer[buffer_size - 1] = '\n';
334
335   pthread_mutex_lock (&lock);
336
337   if (sd < 0)
338   {
339     pthread_mutex_unlock (&lock);
340     return (ENOTCONN);
341   }
342
343   status = swrite (buffer, buffer_size);
344   if (status != 0)
345   {
346     pthread_mutex_unlock (&lock);
347     return (status);
348   }
349
350   status = sread (buffer, sizeof (buffer));
351   if (status < 0)
352   {
353     status = errno;
354     pthread_mutex_unlock (&lock);
355     return (status);
356   }
357   else if (status == 0)
358   {
359     pthread_mutex_unlock (&lock);
360     return (ENODATA);
361   }
362
363   pthread_mutex_unlock (&lock);
364
365   status = atoi (buffer);
366   return (status);
367 } /* }}} int rrdc_update */
368
369 int rrdc_flush (const char *filename) /* {{{ */
370 {
371   char buffer[4096];
372   char *buffer_ptr;
373   size_t buffer_free;
374   size_t buffer_size;
375   int status;
376
377   if (filename == NULL)
378     return (-1);
379
380   memset (buffer, 0, sizeof (buffer));
381   buffer_ptr = &buffer[0];
382   buffer_free = sizeof (buffer);
383
384   status = buffer_add_string ("flush", &buffer_ptr, &buffer_free);
385   if (status != 0)
386     return (ENOBUFS);
387
388   status = buffer_add_string (filename, &buffer_ptr, &buffer_free);
389   if (status != 0)
390     return (ENOBUFS);
391
392   assert (buffer_free < sizeof (buffer));
393   buffer_size = sizeof (buffer) - buffer_free;
394   assert (buffer[buffer_size - 1] == ' ');
395   buffer[buffer_size - 1] = '\n';
396
397   pthread_mutex_lock (&lock);
398
399   if (sd < 0)
400   {
401     pthread_mutex_unlock (&lock);
402     return (ENOTCONN);
403   }
404
405   status = swrite (buffer, buffer_size);
406   if (status != 0)
407   {
408     pthread_mutex_unlock (&lock);
409     return (status);
410   }
411
412   status = sread (buffer, sizeof (buffer));
413   if (status < 0)
414   {
415     status = errno;
416     pthread_mutex_unlock (&lock);
417     return (status);
418   }
419   else if (status == 0)
420   {
421     pthread_mutex_unlock (&lock);
422     return (ENODATA);
423   }
424
425   pthread_mutex_unlock (&lock);
426
427   status = atoi (buffer);
428   return (status);
429 } /* }}} int rrdc_flush */
430
431 /*
432  * vim: set sw=2 sts=2 ts=8 et fdm=marker :
433  */