poll() uses msecs as timeout
[elliptics.git] / example / common.c
blobc6d3aafcd9b521e68ac38d18e528eeea56056dac
1 /*
2 * 2008+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/socket.h>
19 #include <sys/time.h>
20 #include <sys/syscall.h>
22 #include <ctype.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <pthread.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <syslog.h>
30 #include <time.h>
31 #include <unistd.h>
33 #include <netinet/in.h>
35 #include <elliptics/packet.h>
36 #include <elliptics/interface.h>
38 #include "common.h"
40 #define DNET_CONF_COMMENT '#'
41 #define DNET_CONF_DELIM '='
42 #define DNET_CONF_TIME_DELIM '.'
44 int dnet_parse_groups(char *value, int **groupsp)
46 int len = strlen(value), i, num = 0, start = 0, pos = 0;
47 char *ptr = value;
48 int *groups;
50 if (sscanf(value, "auto%d", &num) == 1) {
51 *groupsp = NULL;
52 return num;
55 for (i=0; i<len; ++i) {
56 if (value[i] == DNET_CONF_ADDR_DELIM)
57 start = 0;
58 else if (!start) {
59 start = 1;
60 num++;
64 if (!num) {
65 fprintf(stderr, "no groups found\n");
66 return -ENOENT;
69 groups = malloc(sizeof(int) * num);
70 if (!groups)
71 return -ENOMEM;
73 memset(groups, 0, num * sizeof(int));
75 start = 0;
76 for (i=0; i<len; ++i) {
77 if (value[i] == DNET_CONF_ADDR_DELIM) {
78 value[i] = '\0';
79 if (start) {
80 groups[pos] = atoi(ptr);
81 pos++;
82 start = 0;
84 } else if (!start) {
85 ptr = &value[i];
86 start = 1;
90 if (start) {
91 groups[pos] = atoi(ptr);
92 pos++;
95 *groupsp = groups;
96 return pos;
99 int dnet_parse_numeric_id(char *value, unsigned char *id)
101 unsigned char ch[5];
102 unsigned int i, len = strlen(value);
104 memset(id, 0, DNET_ID_SIZE);
106 if (len/2 > DNET_ID_SIZE)
107 len = DNET_ID_SIZE * 2;
109 ch[0] = '0';
110 ch[1] = 'x';
111 ch[4] = '\0';
112 for (i=0; i<len / 2; i++) {
113 ch[2] = value[2*i + 0];
114 ch[3] = value[2*i + 1];
116 id[i] = (unsigned char)strtol((const char *)ch, NULL, 16);
119 if (len & 1) {
120 ch[2] = value[2*i + 0];
121 ch[3] = '0';
123 id[i] = (unsigned char)strtol((const char *)ch, NULL, 16);
126 return 0;
129 void dnet_common_log(void *priv, int level, const char *msg)
131 char str[64];
132 struct tm tm;
133 struct timeval tv;
134 FILE *stream = priv;
136 if (!stream)
137 stream = stdout;
139 gettimeofday(&tv, NULL);
140 localtime_r((time_t *)&tv.tv_sec, &tm);
141 strftime(str, sizeof(str), "%F %R:%S", &tm);
143 fprintf(stream, "%s.%06lu %ld/%4d %1d: %s", str, tv.tv_usec, dnet_get_id(), getpid(), level, msg);
144 fflush(stream);
147 void dnet_syslog(void *priv __attribute__ ((unused)), int level, const char *msg)
149 int prio = LOG_DEBUG;
150 char str[64];
151 struct tm tm;
152 struct timeval tv;
154 if (level == DNET_LOG_ERROR)
155 prio = LOG_ERR;
156 if (level == DNET_LOG_INFO)
157 prio = LOG_INFO;
159 gettimeofday(&tv, NULL);
160 localtime_r((time_t *)&tv.tv_sec, &tm);
161 strftime(str, sizeof(str), "%F %R:%S", &tm);
163 syslog(prio, "%s.%06lu %ld/%4d %1x: %s", str, tv.tv_usec, dnet_get_id(), getpid(), level, msg);
166 int dnet_common_add_remote_addr(struct dnet_node *n, struct dnet_config *main_cfg, char *orig_addr)
168 char *a;
169 char *addr, *p;
170 int added = 0, err;
171 struct dnet_config cfg;
172 char auto_str[] = "autodiscovery:";
173 int auto_len = strlen(auto_str);
175 if (!orig_addr)
176 return 0;
178 a = strdup(orig_addr);
179 if (!a) {
180 err = -ENOMEM;
181 goto err_out_exit;
184 addr = a;
186 while (addr) {
187 int autodescovery = 0;
189 p = strchr(addr, ' ');
190 if (p)
191 *p++ = '\0';
193 memcpy(&cfg, main_cfg, sizeof(struct dnet_config));
195 if (!strncmp(addr, auto_str, auto_len)) {
196 addr[auto_len - 1] = '\0';
197 addr += auto_len;
198 autodescovery = 1;
201 err = dnet_parse_addr(addr, &cfg);
202 if (err) {
203 dnet_log_raw(n, DNET_LOG_ERROR, "Failed to parse addr '%s': %d.\n", addr, err);
204 goto next;
207 if (autodescovery) {
208 err = dnet_discovery_add(n, &cfg);
209 if (err)
210 goto next;
211 } else {
212 err = dnet_add_state(n, &cfg);
213 if (err)
214 goto next;
217 added++;
219 if (!p)
220 break;
222 next:
223 addr = p;
225 while (addr && *addr && isspace(*addr))
226 addr++;
229 free(a);
231 if (!added) {
232 err = 0;
233 dnet_log_raw(n, DNET_LOG_ERROR, "No remote addresses added. Continue to work though.\n");
234 goto err_out_exit;
237 return 0;
239 err_out_exit:
240 return err;
243 int dnet_common_prepend_data(struct timespec *ts, uint64_t size, void *buf, int *bufsize)
245 void *orig = buf;
246 struct dnet_common_embed *e = buf;
247 uint64_t *edata = (uint64_t *)e->data;
249 if (*bufsize < (int)(sizeof(struct dnet_common_embed) + sizeof(uint64_t)) * 2)
250 return -ENOBUFS;
252 e->size = sizeof(uint64_t) * 2;
253 e->type = DNET_FCGI_EMBED_TIMESTAMP;
254 e->flags = 0;
255 dnet_common_convert_embedded(e);
257 edata[0] = dnet_bswap64(ts->tv_sec);
258 edata[1] = dnet_bswap64(ts->tv_nsec);
260 buf += sizeof(struct dnet_common_embed) + sizeof(uint64_t) * 2;
262 e = buf;
263 e->size = size;
264 e->type = DNET_FCGI_EMBED_DATA;
265 e->flags = 0;
266 dnet_common_convert_embedded(e);
268 buf += sizeof(struct dnet_common_embed);
270 *bufsize = buf - orig;
271 return 0;
274 #define dnet_map_log(n, level, fmt, a...) do { if ((n)) dnet_log_raw((n), level, fmt, ##a); else fprintf(stderr, fmt, ##a); } while (0)
276 int dnet_map_history(struct dnet_node *n, char *file, struct dnet_history_map *map)
278 int err;
279 struct stat st;
281 map->fd = open(file, O_RDWR | O_CLOEXEC);
282 if (map->fd < 0) {
283 err = -errno;
284 dnet_map_log(n, DNET_LOG_ERROR, "Failed to open history file '%s': %s [%d].\n",
285 file, strerror(errno), errno);
286 goto err_out_exit;
289 err = fstat(map->fd, &st);
290 if (err) {
291 err = -errno;
292 dnet_map_log(n, DNET_LOG_ERROR, "Failed to stat history file '%s': %s [%d].\n",
293 file, strerror(errno), errno);
294 goto err_out_close;
297 if (st.st_size % (int)sizeof(struct dnet_history_entry)) {
298 dnet_map_log(n, DNET_LOG_ERROR, "Corrupted history file '%s', "
299 "its size %llu must be multiple of %zu.\n",
300 file, (unsigned long long)st.st_size,
301 sizeof(struct dnet_history_entry));
302 err = -EINVAL;
303 goto err_out_close;
305 map->size = st.st_size;
307 map->ent = mmap(NULL, map->size, PROT_READ | PROT_WRITE, MAP_SHARED, map->fd, 0);
308 if (map->ent == MAP_FAILED) {
309 err = -errno;
310 dnet_map_log(n, DNET_LOG_ERROR, "Failed to mmap history file '%s': %s [%d].\n",
311 file, strerror(errno), errno);
312 goto err_out_close;
315 map->num = map->size / sizeof(struct dnet_history_entry);
317 dnet_map_log(n, DNET_LOG_NOTICE, "Mapped %ld entries in '%s'.\n", map->num, file);
319 return 0;
321 err_out_close:
322 close(map->fd);
323 err_out_exit:
324 return err;
327 void dnet_unmap_history(struct dnet_node *n __attribute((unused)), struct dnet_history_map *map)
329 munmap(map->ent, map->size);
330 close(map->fd);
333 struct dnet_meta * dnet_meta_search_cust(struct dnet_meta_container *mc, uint32_t type)
335 void *data = mc->data;
336 uint32_t size = mc->size;
337 struct dnet_meta m, *found = NULL;
339 while (size) {
340 if (size < sizeof(struct dnet_meta)) {
341 fprintf(stderr, "Metadata size %u is too small, min %zu, searching for 0x%x.\n",
342 size, sizeof(struct dnet_meta), type);
343 break;
346 m = *(struct dnet_meta *)data;
347 dnet_convert_meta(&m);
349 if (m.size + sizeof(struct dnet_meta) > size) {
350 fprintf(stderr, "Metadata entry broken: entry size %u, type: 0x%x, struct size: %zu, "
351 "total size left: %u, searching for 0x%x.\n",
352 m.size, m.type, sizeof(struct dnet_meta), size, type);
353 break;
356 if (m.type == type) {
357 found = data;
358 break;
361 data += m.size + sizeof(struct dnet_meta);
362 size -= m.size + sizeof(struct dnet_meta);
365 return found;
368 int dnet_background(void)
370 pid_t pid;
371 int fd;
373 pid = fork();
374 if (pid == -1) {
375 fprintf(stderr, "Failed to fork to background: %s.\n", strerror(errno));
376 return -1;
379 if (pid != 0) {
380 printf("Daemon pid: %d.\n", pid);
381 exit(0);
384 setsid();
386 close(0);
387 close(1);
388 close(2);
390 fd = open("/dev/null", O_RDWR);
391 if (fd < 0) {
392 fd = -errno;
393 fprintf(stderr, "Can not open /dev/null: %d\n", fd);
394 exit(fd);
397 dup2(fd, 0);
398 dup2(fd, 1);
399 dup2(fd, 2);
401 return 0;