segfault/memleak on incorrect data fixed
[elliptics.git] / example / find.cpp
blob0b9d21c4c47148f7dc360484763b2a8a6523d7aa
1 /*
2 * 2011+ 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 #define _XOPEN_SOURCE 600
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/socket.h>
21 #include <sys/mman.h>
22 #include <sys/wait.h>
24 #include <errno.h>
25 #include <ctype.h>
26 #include <dirent.h>
27 #include <fcntl.h>
28 #include <pthread.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
34 #include <sstream>
35 #include <stdexcept>
37 #include "elliptics/interface.h"
38 #include "elliptics/packet.h"
39 #include "elliptics/cppdef.h"
41 #include "common.h"
43 using namespace ioremap::elliptics;
45 class finder : public session {
46 public:
47 finder(node &n) : session(n) {};
48 virtual ~finder() {};
50 void add_remote(const char *addr);
52 void parse_lookup(const std::string &ret);
53 void parse_meta(const std::string &ret);
56 void finder::add_remote(const char *addr)
58 struct dnet_config rem;
59 int err;
61 memset(&rem, 0, sizeof(rem));
63 err = dnet_parse_addr((char *)addr, &rem);
64 if (err < 0) {
65 std::ostringstream str;
66 str << "Failed to parse addr: " << addr;
67 throw std::runtime_error(str.str());
70 m_node->add_remote(rem.addr, atoi(rem.port), rem.family);
73 void finder::parse_lookup(const std::string &ret)
75 long size = ret.size();
76 void *data = (void *)ret.data();
78 while (size) {
79 struct dnet_addr *addr = (struct dnet_addr *)data;
80 struct dnet_cmd *cmd = (struct dnet_cmd *)(addr + 1);
82 if (cmd->size) {
83 struct dnet_file_info *info = NULL;
84 char addr_str[128] = "no-address";
86 if (cmd->size >= sizeof(struct dnet_addr_attr)) {
87 struct dnet_addr_attr *a = (struct dnet_addr_attr *)(cmd + 1);
89 if (cmd->size > sizeof(struct dnet_addr_attr) + sizeof(struct dnet_file_info)) {
90 info = (struct dnet_file_info *)(a + 1);
91 dnet_convert_file_info(info);
94 dnet_convert_addr_attr(a);
95 dnet_server_convert_dnet_addr_raw(&a->addr, addr_str, sizeof(addr_str));
98 std::string route_addr = "failed to get route table";
100 try {
101 route_addr = lookup_addr(cmd->id);
102 } catch (const std::exception &e) {
105 if (!info)
106 dnet_log_raw(get_node(), DNET_LOG_DATA, "%s: FIND object: %s: should live at: %s\n",
107 dnet_dump_id(&cmd->id), addr_str, route_addr.c_str());
108 else
109 dnet_log_raw(get_node(), DNET_LOG_DATA, "%s: FIND-OK object: %s: should live at: %s, "
110 "offset: %llu, size: %llu, mode: %llo, path: %s\n",
111 dnet_dump_id(&cmd->id), addr_str, route_addr.c_str(),
112 (unsigned long long)info->offset, (unsigned long long)info->size,
113 (unsigned long long)info->mode, (char *)(info + 1));
114 } else {
115 if (cmd->status != 0)
116 dnet_log_raw(get_node(), DNET_LOG_DATA, "%s: FIND object: status: %d\n", dnet_dump_id(&cmd->id), cmd->status);
119 data = (char *)data + sizeof(struct dnet_addr) + sizeof(struct dnet_cmd) + cmd->size;
120 size -= sizeof(struct dnet_addr) + sizeof(struct dnet_cmd) + cmd->size;
124 void finder::parse_meta(const std::string &ret)
126 long size = ret.size();
127 void *data = (void *)ret.data();
129 while (size) {
130 struct dnet_addr *addr = (struct dnet_addr *)data;
131 struct dnet_cmd *cmd = (struct dnet_cmd *)(addr + 1);
132 char addr_str[128];
134 dnet_server_convert_dnet_addr_raw(addr, addr_str, sizeof(addr_str));
136 if (cmd->size > sizeof(struct dnet_io_attr)) {
137 struct dnet_io_attr *io = (struct dnet_io_attr *)(cmd + 1);
139 dnet_convert_io_attr(io);
141 dnet_log_raw(get_node(), DNET_LOG_DATA, "%s: FIND-OK meta: %s: cmd: %s, io size: %llu\n",
142 dnet_dump_id(&cmd->id), addr_str, dnet_cmd_string(cmd->cmd),
143 (unsigned long long)io->size);
145 struct dnet_meta_container mc;
146 memset(&mc, 0, sizeof(mc));
147 mc.data = io + 1;
148 mc.size = io->size;
150 memcpy(&mc.id, &cmd->id, sizeof(struct dnet_id));
151 dnet_meta_print(m_session, &mc);
152 } else {
153 if (cmd->status != 0)
154 dnet_log_raw(get_node(), DNET_LOG_DATA, "%s: FIND meta: %s: status: %d\n",
155 dnet_dump_id(&cmd->id), addr_str, cmd->status);
158 data = (char *)data + sizeof(struct dnet_addr) + sizeof(struct dnet_cmd) + cmd->size;
159 size -= sizeof(struct dnet_addr) + sizeof(struct dnet_cmd) + cmd->size;
163 static __attribute__ ((noreturn)) void efinder_usage(const char *p)
165 fprintf(stderr, "Usage: %s <options>\n"
166 " -r addr:port:family - remote node to connect\n"
167 " -l log - log file\n"
168 " -m level - log level\n"
169 " -I id - object ID\n"
170 " -h - this help\n"
171 , p);
172 exit(-1);
175 int main(int argc, char *argv[])
177 int ch, err;
178 char *logfile = (char *)"/dev/stderr";
179 int log_level = DNET_LOG_ERROR;
180 char *remote = NULL;
181 struct dnet_id raw;
182 struct dnet_trans_control ctl;
184 while ((ch = getopt(argc, argv, "r:l:m:I:h")) != -1) {
185 switch (ch) {
186 case 'r':
187 remote = optarg;
188 break;
189 case 'l':
190 logfile = optarg;
191 break;
192 case 'm':
193 log_level = strtoul(optarg, NULL, 0);
194 break;
195 case 'I':
196 err = dnet_parse_numeric_id(optarg, raw.id);
197 if (err < 0)
198 return err;
199 break;
200 case 'h':
201 default:
202 efinder_usage(argv[0]);
207 if (!remote) {
208 fprintf(stderr, "You must specify remote addr and object ID\n");
209 efinder_usage(argv[0]);
212 try {
213 log_file log(logfile, log_level);
214 node n(log);
215 finder find(n);
217 find.add_remote(remote);
220 callback c;
222 memset(&ctl, 0, sizeof(struct dnet_trans_control));
224 ctl.priv = (void *)&c;
225 ctl.complete = callback::complete_callback;
227 dnet_setup_id(&ctl.id, 0, raw.id);
228 ctl.cflags = DNET_FLAGS_DIRECT | DNET_FLAGS_NEED_ACK | DNET_ATTR_META_TIMES;
229 ctl.cmd = DNET_CMD_LOOKUP;
231 int num = find.request_cmd(ctl);
232 std::string lookup_ret = c.wait(num);
233 find.parse_lookup(lookup_ret);
239 callback c;
241 memset(&ctl, 0, sizeof(ctl));
243 ctl.priv = (void *)&c;
244 ctl.complete = callback::complete_callback;
246 dnet_setup_id(&ctl.id, 0, raw.id);
247 ctl.cmd = DNET_CMD_READ;
248 ctl.cflags = DNET_FLAGS_DIRECT | DNET_FLAGS_NEED_ACK;
250 struct dnet_io_attr io;
251 memset(&io, 0, sizeof(io));
252 io.flags = DNET_IO_FLAGS_META;
253 memcpy(io.id, ctl.id.id, DNET_ID_SIZE);
254 memcpy(io.parent, ctl.id.id, DNET_ID_SIZE);
255 ctl.data = &io;
256 ctl.size = sizeof(io);
258 int num = find.request_cmd(ctl);
259 std::string meta_ret = c.wait(num);
260 find.parse_meta(meta_ret);
262 } catch (const std::exception &e) {
263 std::cerr << e.what() << std::endl;
266 return 0;