Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
net.cpp
1 
2 /***************************************************************************
3  * net.cpp - Generic network tool
4  *
5  * Created: Fri Nov 16 10:27:57 2007
6  * Copyright 2005-2009 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include <fvutils/net/fuse.h>
24 #include <fvutils/net/fuse_client.h>
25 #include <fvutils/net/fuse_client_handler.h>
26 #include <fvutils/net/fuse_message.h>
27 #include <fvutils/net/fuse_image_content.h>
28 #include <fvutils/net/fuse_lut_content.h>
29 #include <fvutils/net/fuse_imagelist_content.h>
30 #include <fvutils/net/fuse_lutlist_content.h>
31 #include <fvutils/writers/fvraw.h>
32 #include <fvutils/color/colorspaces.h>
33 #include <fvutils/colormap/yuvcm.h>
34 #include <fvutils/colormap/cmfile.h>
35 
36 #include <core/threading/mutex.h>
37 #include <core/threading/wait_condition.h>
38 #include <core/exceptions/software.h>
39 #include <utils/system/argparser.h>
40 #include <utils/system/console_colors.h>
41 
42 #include <netcomm/service_discovery/browse_handler.h>
43 #ifdef HAVE_AVAHI
44 #include <netcomm/dns-sd/avahi_thread.h>
45 #endif
46 
47 // for inet_ntop
48 #include <arpa/inet.h>
49 #include <netinet/in.h>
50 #include <cstring>
51 #include <cstdlib>
52 #include <cstdio>
53 
54 using namespace fawkes;
55 using namespace firevision;
56 
57 /** FireVision Network Tool */
59  : public FuseClientHandler,
61 {
62  public:
63  /** Constructor.
64  * @param argp argument parser
65  */
67  {
68  __argp = argp;
69  __exploring = false;
70  __explore_waitcond = NULL;
71  }
72 
73  void
74  fuse_invalid_server_version(uint32_t local_version,
75  uint32_t remote_version) throw()
76  {
77  printf("Invalid version received (local: %u, remote: %u)\n",
78  local_version, remote_version);
79  }
80 
81  virtual void
83  {
84  }
85 
86  virtual void
88  {
89  }
90 
91  virtual void
93  {
94  // printf("Received message of type %u\n", m->type());
95 
96  switch (m->type() ) {
97  case FUSE_MT_IMAGE:
98  // we got an image, save it to the given file
99  try {
100  FuseImageContent *ic = m->msgc<FuseImageContent>();
101  if ( ic->format() == FUSE_IF_RAW ) {
102  FvRawWriter *w = new FvRawWriter(__file, ic->pixel_width(), ic->pixel_height(),
103  (colorspace_t)ic->colorspace(), ic->buffer());
104  w->write();
105  delete w;
106  } else if ( ic->format() == FUSE_IF_JPEG ) {
107  FILE *f = fopen(__file, "w");
108  if (fwrite(ic->buffer(), ic->buffer_size(), 1, f) == 0) {
109  printf("Failed to write data to file");
110  }
111  fclose(f);
112  } else {
113  printf("Image of unknown format (%u) received.\n", ic->format());
114  }
115  delete ic;
116  } catch (Exception &e) {
117  printf("Received message cannot be casted to FuseImageMessage\n");
118  e.print_trace();
119  }
120  __client->cancel();
121  break;
122  case FUSE_MT_IMAGE_LIST:
123  try {
124  FuseImageListContent *ilc = m->msgc<FuseImageListContent>();
125  if ( ilc->has_next() ) {
126  printf("Available images:\n");
127  while ( ilc->has_next() ) {
128  FUSE_imageinfo_t *ii = ilc->next();
129  char tmp[IMAGE_ID_MAX_LENGTH + 1];
130  tmp[IMAGE_ID_MAX_LENGTH] = 0;
131  strncpy(tmp, ii->image_id, IMAGE_ID_MAX_LENGTH);
132  printf(" %s (%u x %u, %s)\n", tmp, ntohl(ii->width), ntohl(ii->height),
133  colorspace_to_string((colorspace_t)ntohs(ii->colorspace)));
134  }
135  } else {
136  printf("No images available\n");
137  }
138  delete ilc;
139  } catch (Exception &e) {
140  printf("Received message cannot be casted to FuseImageListMessage\n");
141  e.print_trace();
142  }
143  break;
144  case FUSE_MT_LUT_LIST:
145  try {
146  FuseLutListContent *llc = m->msgc<FuseLutListContent>();
147  if ( llc->has_next() ) {
148  printf("Available lookup tables:\n");
149  while ( llc->has_next() ) {
150  FUSE_lutinfo_t *li = llc->next();
151  char tmp[LUT_ID_MAX_LENGTH + 1];
152  tmp[LUT_ID_MAX_LENGTH] = 0;
153  strncpy(tmp, li->lut_id, LUT_ID_MAX_LENGTH);
154  printf(" %s (%u x %u x %u, %u bpc)\n", tmp,
155  ntohl(li->width), ntohl(li->height),
156  ntohl(li->depth), ntohl(li->bytes_per_cell));
157  }
158  } else {
159  printf("No lookup tables available\n");
160  }
161  delete llc;
162  } catch (Exception &e) {
163  printf("Received message cannot be casted to FuseImageListMessage\n");
164  e.print_trace();
165  }
166  __client->cancel();
167  break;
168 
169  case FUSE_MT_LUT:
170  // we got a LUT, save it to the given file
171  try {
172  FuseLutContent *lc = m->msgc<FuseLutContent>();
173  // Currently we expect colormaps, so make sure we get sensible dimensions
174  if ( lc->width() != 256 ) {
175  printf("Invalid dimensions for LUT received, colormap width %u != 256", lc->width());
176  } else if ( lc->height() != 256 ) {
177  printf("Invalid dimensions for LUT received, colormap height %u != 256", lc->height());
178  } else if ( lc->depth() > 256 ) {
179  printf("Invalid dimensions for LUT received, colormap depth %u > 256", lc->depth());
180  } else {
181  try {
182  YuvColormap yuvcm(lc->depth());
183  yuvcm.set(lc->buffer());
184  ColormapFile cmf;
185  cmf.add_colormap(&yuvcm);
186  cmf.write(__file);
187  } catch (Exception &e) {
188  e.append("Failed to save colormap");
189  e.print_trace();
190  }
191  }
192  delete lc;
193  } catch (Exception &e) {
194  printf("Received message cannot be casted to FuseLutMessage\n");
195  e.print_trace();
196  }
197  __client->cancel();
198  break;
199 
200  case FUSE_MT_SET_LUT_SUCCEEDED:
201  {
202  FUSE_lutdesc_message_t *lutdesc = m->msg<FUSE_lutdesc_message_t>();
203  char lut_id[LUT_ID_MAX_LENGTH + 1];
204  lut_id[LUT_ID_MAX_LENGTH] = 0;
205  strncpy(lut_id, lutdesc->lut_id, LUT_ID_MAX_LENGTH);
206  printf("LUT %s has been uploaded successfully.\n", lut_id);
207  __client->cancel();
208  }
209  break;
210 
211  case FUSE_MT_SET_LUT_FAILED:
212  {
213  FUSE_lutdesc_message_t *lutdesc = m->msg<FUSE_lutdesc_message_t>();
214  char lut_id[LUT_ID_MAX_LENGTH + 1];
215  lut_id[LUT_ID_MAX_LENGTH] = 0;
216  strncpy(lut_id, lutdesc->lut_id, LUT_ID_MAX_LENGTH);
217  printf("LUT upload of %s has failed.\n", lut_id);
218  __client->cancel();
219  }
220  break;
221 
222  default:
223  printf("Unhandled message of type %u received\n", m->type());
224  __client->cancel();
225  break;
226  }
227  }
228 
229 
230  virtual void all_for_now()
231  {
232  printf("All for now\n");
233  __explore_mutex->lock();
234  __explore_waitcond->wake_all();
235  __explore_mutex->unlock();
236  }
237 
238  virtual void cache_exhausted()
239  {
240  }
241 
242  virtual void browse_failed(const char *name,
243  const char *type,
244  const char *domain)
245  {
246  printf("Browsing for %s failed\n", type);
247  }
248 
249  virtual void service_added(const char *name,
250  const char *type,
251  const char *domain,
252  const char *host_name,
253  const struct sockaddr *addr,
254  const socklen_t addr_size,
255  uint16_t port,
256  std::list<std::string> &txt,
257  int flags
258  )
259  {
260  struct sockaddr_in *s;
261  if ( addr_size == sizeof(struct sockaddr_in) ) {
262  s = (struct sockaddr_in *)addr;
263  } else {
264  printf("%s socket data not IPv4, ignoring\n", name);
265  return;
266  }
267 
268  char addrp[INET_ADDRSTRLEN];
269  inet_ntop(AF_INET, &(s->sin_addr), addrp, sizeof(addrp));
270  printf("Found %s%s%s (%s/%s on %hu), querying\n",
271  c_blue, name, c_normal, host_name, addrp, port);
272 
273  __client = new FuseClient(host_name, port, this);
274  __client->connect();
275  __client->start();
276  __client->wait_greeting();
277  show_all();
278  __client->join();
279  delete __client;
280 
281  printf("\n");
282  }
283 
284  virtual void service_removed(const char *name,
285  const char *type,
286  const char *domain)
287  {
288  }
289 
290  /** Print usage message. */
291  void
293  {
294  printf("Usage: %s -i/-c/-C/-s/-e [-n host[:port]/id file]\n"
295  " -i Get image\n"
296  " -j Get JPEG-compressed image\n"
297  " -c Get colormap\n"
298  " -C Set colormap from file\n"
299  " -s Show available images and LUTs\n"
300  " -e Explore network. Will query all instances of Fountain\n"
301  " found on the network for all available images and LUTs.\n"
302  " -n net_string Open network camera, the camera string is of the form\n"
303  " host[:port]/id. You have to specify at least the host\n"
304  " and the id, the port is optional and defaults to 5000\n"
305  " Depending on the operation id is the image or the LUT ID\n"
306  " file File to write incoming data to or to read data to send from\n",
307  __argp->program_name());
308  }
309 
310 
311  /** Request image.
312  * @param image_id Image ID.
313  * @param jpeg if true JPEG images are requested, raw images otherwise
314  */
315  void
316  get_image(const char *image_id, bool jpeg)
317  {
319  memset(idm, 0, sizeof(FUSE_imagereq_message_t));
320  strncpy(idm->image_id, image_id, IMAGE_ID_MAX_LENGTH);
321  idm->format = (jpeg ? FUSE_IF_JPEG : FUSE_IF_RAW);
322  __client->enqueue(FUSE_MT_GET_IMAGE, idm, sizeof(FUSE_imagereq_message_t));
323  }
324 
325  /** Request LUT.
326  * @param lut_id LUT ID.
327  */
328  void
329  get_colormap(const char *lut_id)
330  {
332  memset(ldm, 0, sizeof(FUSE_lutdesc_message_t));
333  strncpy(ldm->lut_id, lut_id, LUT_ID_MAX_LENGTH);
334  __client->enqueue(FUSE_MT_GET_LUT, ldm, sizeof(FUSE_lutdesc_message_t));
335  }
336 
337  /** Upload LUT.
338  * @param lut_id LUT ID.
339  */
340  void
341  set_colormap(const char *lut_id)
342  {
343  ColormapFile cmf;
344  cmf.read(__file);
345  Colormap *cm = cmf.get_colormap();
346  FuseLutContent *lc = new FuseLutContent(lut_id, cm->get_buffer(),
347  cm->width(), cm->height(), cm->depth(),
348  /* bytes per cell */ 1);
349  delete cm;
350 
351  __client->enqueue(new FuseNetworkMessage(FUSE_MT_SET_LUT, lc));
352  }
353 
354  /** Show all images and LUTs. */
355  void
357  {
358  __client->enqueue(FUSE_MT_GET_IMAGE_LIST);
359  __client->enqueue(FUSE_MT_GET_LUT_LIST);
360  }
361 
362  /** Explore network.
363  * This will query via service discovery for all Fountain instances on the local
364  * network. It will then connect to each of these and query them for existing images
365  * and lookup tables.
366  */
367  void
369  {
370 #ifdef HAVE_AVAHI
371  __exploring = true;
372  __explore_mutex = new Mutex();
373  __explore_waitcond = new WaitCondition(__explore_mutex);
374 
375  __explore_mutex->lock();
376 
377  __avahi_thread = new AvahiThread();
378  __avahi_thread->start();
379 
380  __avahi_thread->watch_service("_fountain._tcp", this);
381 
382  __explore_waitcond->wait();
383  delete __explore_waitcond;
384  __explore_mutex->unlock();
385  delete __explore_mutex;
386  __avahi_thread->cancel();
387  __avahi_thread->join();
388  delete __avahi_thread;
389 #else
390  printf("\nExploration is not available because Avahi support is missing. "
391  "Install avahi-devel and recompile.\n\n");
392 #endif
393  }
394 
395  /** Run. */
396  void
397  run()
398  {
399  if ( __argp->has_arg("h") ) {
400  print_usage();
401  exit(0);
402  } else {
403  char *net_string;
404  if ( __argp->has_arg("n") ) {
405  net_string = strdup(__argp->arg("n"));
406  } else {
407  net_string = strdup("localhost");
408  }
409  char *id = NULL, *host = NULL, *port = NULL, *save_ptr = NULL;
410  int port_num = 2208;
411  char *hostport;
412 
413  hostport = strtok_r(net_string, "/", &save_ptr);
414  id = strtok_r(NULL, "", &save_ptr);
415 
416  if ( strchr(hostport, ':') != NULL ) {
417  host = strtok_r(hostport, ":", &save_ptr);
418  port = strtok_r(NULL, "", &save_ptr);
419  } else {
420  host = hostport;
421  }
422 
423  if ( port != NULL ) {
424  port_num = atoi(port);
425  if ( (port_num < 0) || (port_num > 0xFFFF) ) {
426  throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
427  }
428  }
429 
430  if (__argp->has_arg("i") || __argp->has_arg("j") ||
431  __argp->has_arg("c") || __argp->has_arg("C")) {
432  if ( __argp->num_items() == 0 ) {
433  print_usage();
434  printf("\nFile name missing\n\n");
435  exit(1);
436  } else {
437  __file = __argp->items()[0];
438  }
439 
440  if (id == NULL) {
441  print_usage();
442  printf("\nNo Image/LUT ID given, needed for -i/-c/-C\n\n");
443  exit(2);
444  }
445  }
446 
447  if ( ! __argp->has_arg("e") ) {
448  __client = new FuseClient(host, port_num, this);
449  __client->connect();
450  __client->start();
451  __client->wait_greeting();
452  }
453 
454  if ( __argp->has_arg("i") ) {
455  get_image(id, /* JPEG? */ false);
456  } else if ( __argp->has_arg("j") ) {
457  get_image(id, /* JPEG? */ true);
458  } else if ( __argp->has_arg("c") ) {
459  get_colormap(id);
460  } else if ( __argp->has_arg("C") ) {
461  set_colormap(id);
462  } else if ( __argp->has_arg("s") ) {
463  show_all();
464  } else if ( __argp->has_arg("e") ) {
465  explore_network();
466  } else {
467  print_usage();
468  __client->cancel();
469  }
470 
471  if ( ! __argp->has_arg("e") ) {
472  __client->join();
473  delete __client;
474  }
475 
476  free(net_string);
477  }
478  }
479 
480 private:
481  ArgumentParser *__argp;
482  FuseClient *__client;
483 
484  const char *__file;
485 
486  bool __exploring;
487  Mutex *__explore_mutex;
488  WaitCondition *__explore_waitcond;
489 
490 #ifdef HAVE_AVAHI
491  AvahiThread *__avahi_thread;
492 #endif
493 };
494 
495 
496 int
497 main(int argc, char **argv)
498 {
499  ArgumentParser argp(argc, argv, "hn:icCsej");
500 
501  FireVisionNetworkTool *nettool = new FireVisionNetworkTool(&argp);
502  nettool->run();
503  delete nettool;
504 
505  return 0;
506 }
uint32_t bytes_per_cell
bytes per cell
Definition: fuse.h:180
unsigned int pixel_width() const
Get image width.
size_t buffer_size() const
Get size of buffer.
void get_colormap(const char *lut_id)
Request LUT.
Definition: net.cpp:329
Wait until a given condition holds.
FUSE lookup table content.
void add_colormap(Colormap *colormap)
Add colormap.
Definition: cmfile.cpp:98
Image request message.
Definition: fuse.h:147
void fuse_invalid_server_version(uint32_t local_version, uint32_t remote_version)
Invalid version string received.
Definition: net.cpp:74
Image info message.
Definition: fuse.h:165
virtual unsigned int depth() const =0
Get depth of colormap.
virtual void all_for_now()
All results have been retrieved.
Definition: net.cpp:230
void get_image(const char *image_id, bool jpeg)
Request image.
Definition: net.cpp:316
uint32_t height
height of LUT
Definition: fuse.h:178
Parse command line arguments.
Definition: argparser.h:66
Colormap interface.
Definition: colormap.h:38
virtual unsigned int height() const =0
Get height of colormap.
FUSE_lutinfo_t * next()
Get next LUT info.
static const char * c_blue
Print blue on console.
uint32_t width
width of LUT
Definition: fuse.h:177
Colormap * get_colormap()
Get a freshly generated colormap based on current file content.
Definition: cmfile.cpp:169
virtual void service_added(const char *name, const char *type, const char *domain, const char *host_name, const struct sockaddr *addr, const socklen_t addr_size, uint16_t port, std::list< std::string > &txt, int flags)
A service has been announced on the network.
Definition: net.cpp:249
YUV Colormap.
Definition: yuvcm.h:39
Interface for class that process browse results.
uint32_t width
width in pixels
Definition: fuse.h:169
virtual void fuse_connection_established()
Connection has been established.
Definition: net.cpp:82
virtual void service_removed(const char *name, const char *type, const char *domain)
A service has been removed from the network.
Definition: net.cpp:284
uint32_t colorspace
color space
Definition: fuse.h:167
virtual void write(const char *file_name)
Write file.
Definition: fvfile.cpp:262
virtual void read(const char *file_name)
Read file.
Definition: fvfile.cpp:308
void set_colormap(const char *lut_id)
Upload LUT.
Definition: net.cpp:341
char image_id[IMAGE_ID_MAX_LENGTH]
image ID
Definition: fuse.h:166
Colormap file.
Definition: cmfile.h:55
void run()
Run.
Definition: net.cpp:397
FUSE Network Message.
Definition: fuse_message.h:41
FvRaw Writer implementation.
Definition: fvraw.h:34
FireVisionNetworkTool(ArgumentParser *argp)
Constructor.
Definition: net.cpp:66
Base class for exceptions in Fawkes.
Definition: exception.h:36
LUT info message.
Definition: fuse.h:175
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:176
FUSE lookup table list content.
virtual void set(unsigned int y, unsigned int u, unsigned int v, color_t c)
Set color class for given YUV value.
Definition: yuvcm.cpp:182
virtual void write()
Write to file.
Definition: fvraw.cpp:128
unsigned int height() const
Height of LUT.
bool has_next()
Check if another image info is available.
char image_id[IMAGE_ID_MAX_LENGTH]
image ID
Definition: fuse.h:148
Avahi main thread.
Definition: avahi_thread.h:55
void explore_network()
Explore network.
Definition: net.cpp:368
unsigned int width() const
Width of LUT.
virtual void fuse_connection_died()
Connection died.
Definition: net.cpp:87
virtual unsigned int width() const =0
Get width of colormap.
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:619
char lut_id[LUT_ID_MAX_LENGTH]
LUT ID.
Definition: fuse.h:161
uint32_t format
requested image format, see FUSE_image_format_t
Definition: fuse.h:149
virtual void cache_exhausted()
Cache exhausted.
Definition: net.cpp:238
uint32_t height
height in pixels
Definition: fuse.h:170
unsigned char * buffer() const
Image buffer.
bool has_next()
Check if another LUT info is available.
unsigned int depth() const
Depth of LUT.
unsigned char * buffer() const
Get buffer.
void print_usage()
Print usage message.
Definition: net.cpp:292
virtual unsigned char * get_buffer() const =0
Get the raw buffer of this colormap.
virtual void fuse_inbound_received(FuseNetworkMessage *m)
Message received.
Definition: net.cpp:92
virtual void browse_failed(const char *name, const char *type, const char *domain)
Failed to browse for a given service.
Definition: net.cpp:242
Mutex mutual exclusion lock.
Definition: mutex.h:32
Index out of bounds.
Definition: software.h:88
uint32_t depth
depth of LUT
Definition: fuse.h:179
FireVision Network Tool.
Definition: net.cpp:58
unsigned int pixel_height() const
Get image height.
FUSE_imageinfo_t * next()
Get next image info.
unsigned int format() const
Get image format.
unsigned int colorspace() const
Get colorspace.
static const char * c_normal
Print normal on console, without colors, depends on console settings.
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:341
LUT description message.
Definition: fuse.h:160
void show_all()
Show all images and LUTs.
Definition: net.cpp:356