|
1 /* |
|
2 * Copyright 2004-2006 Intel Corporation |
|
3 * |
|
4 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 * you may not use this file except in compliance with the License. |
|
6 * You may obtain a copy of the License at |
|
7 * |
|
8 * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 * |
|
10 * Unless required by applicable law or agreed to in writing, software |
|
11 * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 * See the License for the specific language governing permissions and |
|
14 * limitations under the License. |
|
15 */ |
|
16 |
|
17 #ifdef HAVE_CONFIG_H |
|
18 # include <dtn-config.h> |
|
19 #endif |
|
20 |
|
21 #include <stdio.h> |
|
22 #include <stdlib.h> |
|
23 #include <string.h> |
|
24 #include <strings.h> |
|
25 #include <time.h> |
|
26 #include <unistd.h> |
|
27 #include <errno.h> |
|
28 #include <sys/types.h> |
|
29 #include <sys/stat.h> |
|
30 #include <sys/time.h> |
|
31 #include "dtn_api.h" |
|
32 |
|
33 #define BUFSIZE 16 |
|
34 #define BUNDLE_DIR_DEFAULT INSTALL_LOCALSTATEDIR "/dtn/dtncpd-incoming" |
|
35 |
|
36 static const char *progname; |
|
37 |
|
38 void |
|
39 usage() |
|
40 { |
|
41 fprintf(stderr, "usage: %s [ directory ]\n", progname); |
|
42 fprintf(stderr, " optional directory parameter is where incoming " |
|
43 "files will get put\n"); |
|
44 fprintf(stderr, " (defaults to: %s)\n", BUNDLE_DIR_DEFAULT); |
|
45 exit(1); |
|
46 } |
|
47 |
|
48 int |
|
49 main(int argc, const char** argv) |
|
50 { |
|
51 int i; |
|
52 int ret; |
|
53 dtn_handle_t handle; |
|
54 dtn_endpoint_id_t local_eid; |
|
55 dtn_reg_info_t reginfo; |
|
56 dtn_reg_id_t regid; |
|
57 dtn_bundle_spec_t bundle; |
|
58 dtn_bundle_payload_t payload; |
|
59 const char* endpoint_demux; |
|
60 int debug = 1; |
|
61 |
|
62 char * bundle_dir = 0; |
|
63 |
|
64 char host[PATH_MAX]; |
|
65 int host_len; |
|
66 char * dirpath; |
|
67 char * filename; |
|
68 char filepath[PATH_MAX]; |
|
69 time_t current; |
|
70 |
|
71 char * buffer; |
|
72 char s_buffer[BUFSIZE + 1]; |
|
73 |
|
74 int bufsize, marker, maxwrite; |
|
75 |
|
76 FILE * target; |
|
77 |
|
78 // force stdout to always be line buffered, even if output is |
|
79 // redirected to a pipe or file |
|
80 setvbuf(stdout, (char *)NULL, _IOLBF, 0); |
|
81 |
|
82 s_buffer[BUFSIZE] = '\0'; |
|
83 |
|
84 struct stat st; |
|
85 |
|
86 progname = argv[0]; |
|
87 |
|
88 if (argc > 2) { |
|
89 usage(); |
|
90 } |
|
91 else if (argc == 2) |
|
92 { |
|
93 if (argv[1][0] == '-') { |
|
94 usage(); |
|
95 } |
|
96 bundle_dir = (char *) argv[1]; |
|
97 } |
|
98 else |
|
99 { |
|
100 bundle_dir = BUNDLE_DIR_DEFAULT; |
|
101 } |
|
102 |
|
103 if (access(bundle_dir, W_OK | X_OK) == -1) { |
|
104 fprintf(stderr, "can't access directory '%s': %s\n", |
|
105 bundle_dir, strerror(errno)); |
|
106 usage(); |
|
107 } |
|
108 |
|
109 if (stat(bundle_dir, &st) == -1) { |
|
110 fprintf(stderr, "can't stat directory '%s': %s\n", |
|
111 bundle_dir, strerror(errno)); |
|
112 usage(); |
|
113 } |
|
114 |
|
115 if (!S_ISDIR(st.st_mode)) { |
|
116 fprintf(stderr, "path '%s' is not a directory\n", |
|
117 bundle_dir); |
|
118 usage(); |
|
119 } |
|
120 |
|
121 // open the ipc handle |
|
122 if (debug) printf("opening connection to dtn router...\n"); |
|
123 int err = dtn_open(&handle); |
|
124 if (err != DTN_SUCCESS) { |
|
125 fprintf(stderr, "fatal error opening dtn handle: %s\n", |
|
126 dtn_strerror(err)); |
|
127 exit(1); |
|
128 } |
|
129 |
|
130 // build a local eid based on the configuration of our dtn |
|
131 // router plus the demux string |
|
132 endpoint_demux = "/dtncp/recv?file=*"; |
|
133 dtn_build_local_eid(handle, &local_eid, endpoint_demux); |
|
134 if (debug) printf("local_eid [%s]\n", local_eid.uri); |
|
135 |
|
136 // try to find an existin registration, or create a new |
|
137 // registration based on this eid |
|
138 ret = dtn_find_registration(handle, &local_eid, ®id); |
|
139 if (ret == 0) { |
|
140 if (debug) printf("dtn_find_registration succeeded, regid 0x%x\n", |
|
141 regid); |
|
142 |
|
143 // bind the current handle to the new registration |
|
144 dtn_bind(handle, regid); |
|
145 |
|
146 } else if (dtn_errno(handle) == DTN_ENOTFOUND) { |
|
147 memset(®info, 0, sizeof(reginfo)); |
|
148 dtn_copy_eid(®info.endpoint, &local_eid); |
|
149 reginfo.flags = DTN_REG_DEFER; |
|
150 reginfo.regid = DTN_REGID_NONE; |
|
151 reginfo.expiration = 60 * 60; |
|
152 if ((ret = dtn_register(handle, ®info, ®id)) != 0) { |
|
153 fprintf(stderr, "error creating registration: %d (%s)\n", |
|
154 ret, dtn_strerror(dtn_errno(handle))); |
|
155 exit(1); |
|
156 } |
|
157 |
|
158 if (debug) printf("dtn_register succeeded, regid 0x%x\n", regid); |
|
159 |
|
160 } else { |
|
161 fprintf(stderr, "error in dtn_find_registration: %s", |
|
162 dtn_strerror(dtn_errno(handle))); |
|
163 exit(1); |
|
164 } |
|
165 |
|
166 // loop waiting for bundles |
|
167 while(1) |
|
168 { |
|
169 // change this to _MEM here to receive into memory then write the file |
|
170 // ourselves. (So this code shows both ways to do it.) |
|
171 // XXX/demmer better would be to have a cmd line option |
|
172 dtn_bundle_payload_location_t file_or_mem = DTN_PAYLOAD_FILE; |
|
173 |
|
174 memset(&bundle, 0, sizeof(bundle)); |
|
175 memset(&payload, 0, sizeof(payload)); |
|
176 memset(&dirpath, 0, sizeof(dirpath)); |
|
177 memset(&filename, 0, sizeof(filename)); |
|
178 memset(&filepath, 0, sizeof(filepath)); |
|
179 memset(&host, 0, sizeof(host)); |
|
180 memset(&st, 0, sizeof(st)); |
|
181 |
|
182 printf("dtn_recv [%s]...\n", local_eid.uri); |
|
183 |
|
184 if ((ret = dtn_recv(handle, &bundle, |
|
185 file_or_mem, &payload, -1)) < 0) |
|
186 { |
|
187 fprintf(stderr, "error getting recv reply: %d (%s)\n", |
|
188 ret, dtn_strerror(dtn_errno(handle))); |
|
189 exit(1); |
|
190 } |
|
191 |
|
192 // mark time received |
|
193 current = time(NULL); |
|
194 |
|
195 if (strncmp(bundle.source.uri, "dtn://", 6) != 0) |
|
196 { |
|
197 fprintf(stderr, "bundle source uri '%s' must be a dtn:// uri\n", |
|
198 bundle.source.uri); |
|
199 exit(1); |
|
200 } |
|
201 |
|
202 // grab the sending authority and service tag (i.e. the path) |
|
203 host_len = strchr(&bundle.source.uri[6], '/') - &bundle.source.uri[6]; |
|
204 strncpy(host, &bundle.source.uri[6], host_len); |
|
205 |
|
206 // extract directory from destination path (everything |
|
207 // following std demux, except the '*') |
|
208 endpoint_demux = "/dtncp/recv?file="; |
|
209 dirpath = strstr(bundle.dest.uri, endpoint_demux); |
|
210 if (!dirpath) { |
|
211 fprintf(stderr, "can't find %s demux in uri '%s'\n", |
|
212 endpoint_demux, bundle.dest.uri); |
|
213 exit(1); |
|
214 } |
|
215 |
|
216 dirpath += strlen(endpoint_demux); // skip std demux |
|
217 if (dirpath[0] == '/') dirpath++; // skip leading slash |
|
218 |
|
219 // filename is everything following last / |
|
220 filename = strrchr(dirpath, '/'); |
|
221 if (filename == 0) |
|
222 { |
|
223 filename = dirpath; |
|
224 dirpath = ""; |
|
225 } |
|
226 else |
|
227 { |
|
228 filename[0] = '\0'; // null terminate path |
|
229 filename++; // next char; |
|
230 } |
|
231 |
|
232 // recursively create full directory path |
|
233 // XXX/demmer system -- yuck! |
|
234 sprintf(filepath, "mkdir -p %s/%s/%s", bundle_dir, host, dirpath); |
|
235 system(filepath); |
|
236 |
|
237 // create file name |
|
238 sprintf(filepath, "%s/%s/%s/%s", bundle_dir, host, dirpath, filename); |
|
239 |
|
240 // bundle name is the name of the bundle payload file |
|
241 buffer = payload.filename.filename_val; |
|
242 // bufsize is the length of the payload file (not what we want to print) |
|
243 bufsize = payload.filename.filename_len; |
|
244 // st contains (among other things) size of payload file |
|
245 ret = stat(buffer, &st); |
|
246 |
|
247 printf ("======================================\n"); |
|
248 printf (" File Received at %s\n", ctime(¤t)); |
|
249 printf (" host : %s\n", host); |
|
250 printf (" path : %s\n", dirpath); |
|
251 printf (" file : %s\n", filename); |
|
252 printf (" loc : %s\n", filepath); |
|
253 printf (" size : %d bytes\n", (int) st.st_size); |
|
254 |
|
255 |
|
256 if (file_or_mem == DTN_PAYLOAD_FILE) { |
|
257 int cmdlen = 5 + strlen(buffer) + strlen(filepath); |
|
258 char *cmd = malloc(cmdlen); |
|
259 |
|
260 if (cmd) { |
|
261 snprintf(cmd, cmdlen, "mv %.*s %s", bufsize, buffer, |
|
262 filepath); |
|
263 system(cmd); |
|
264 printf("Moving payload to final filename: '%s'\n", cmd); |
|
265 free(cmd); |
|
266 } else { |
|
267 printf("Out of memory. Find file in %*s.\n", bufsize, |
|
268 buffer); |
|
269 } |
|
270 } else { |
|
271 |
|
272 target = fopen(filepath, "w"); |
|
273 |
|
274 if (target == NULL) |
|
275 { |
|
276 fprintf(stderr, "Error opening file for writing %s\n", |
|
277 filepath); |
|
278 continue; |
|
279 } |
|
280 if (debug) printf ("--------------------------------------\n"); |
|
281 |
|
282 marker = 0; |
|
283 while (marker < bufsize) |
|
284 { |
|
285 // write 256 bytes at a time |
|
286 i=0; |
|
287 maxwrite = (marker + 256) > bufsize? bufsize-marker : 256; |
|
288 while (i < maxwrite) |
|
289 { |
|
290 i += fwrite(buffer + marker + i, 1, maxwrite - i, target); |
|
291 } |
|
292 |
|
293 if (debug) |
|
294 { |
|
295 for (i=0; i < maxwrite; i++) |
|
296 { |
|
297 if (buffer[marker] >= ' ' && buffer[marker] <= '~') |
|
298 s_buffer[marker%BUFSIZE] = buffer[i]; |
|
299 else |
|
300 s_buffer[marker%BUFSIZE] = '.'; |
|
301 |
|
302 if (marker%BUFSIZE == 0) // new line every 16 bytes |
|
303 { |
|
304 printf("%07x ", marker); |
|
305 } |
|
306 else if (marker%2 == 0) |
|
307 { |
|
308 printf(" "); // space every 2 bytes |
|
309 } |
|
310 |
|
311 printf("%02x", buffer[i] & 0xff); |
|
312 |
|
313 // print character summary (a la emacs hexl-mode) |
|
314 if (marker%BUFSIZE == BUFSIZE-1) |
|
315 { |
|
316 printf(" | %s\n", s_buffer); |
|
317 } |
|
318 marker ++; |
|
319 } |
|
320 } |
|
321 else |
|
322 { |
|
323 marker += maxwrite; |
|
324 } |
|
325 } |
|
326 |
|
327 fclose(target); |
|
328 |
|
329 // round off last line |
|
330 if (debug && marker % BUFSIZE != 0) |
|
331 { |
|
332 while (marker % BUFSIZE !=0) |
|
333 { |
|
334 s_buffer[marker%BUFSIZE] = ' '; |
|
335 |
|
336 if (marker%2 == 0) |
|
337 { |
|
338 printf(" "); // space every 2 bytes |
|
339 } |
|
340 |
|
341 printf(" "); |
|
342 |
|
343 // print character summary (a la emacs hexl-mode) |
|
344 if (marker%BUFSIZE == BUFSIZE-1) |
|
345 { |
|
346 printf(" | %s\n", s_buffer); |
|
347 } |
|
348 marker ++; |
|
349 } |
|
350 } |
|
351 printf (" size : %d bytes\n", bufsize); |
|
352 } |
|
353 |
|
354 printf ("======================================\n"); |
|
355 dtn_free_payload(&payload); |
|
356 } |
|
357 |
|
358 dtn_close(handle); |
|
359 |
|
360 return 0; |
|
361 } |