Did you know LQ has a Linux Hardware Compatibility List?
Go Back > Blogs > rainbowsally
User Name


Rate this Entry

Sockets - A Packet Snooper With A QT4 GUI (Req's libLQ-qt/mc2 dload) Part 1

Posted 01-19-2013 at 07:54 AM by rainbowsally
Updated 08-06-2014 at 08:56 AM by rainbowsally (added link to part 2)

Sockets - A Packet Snooper With A QT4 GUI (Req's libLQ-qt/mc2 dload) Part 1

Today's feature is
  • Running a packet snooper in an lqMiniTerm 'run' loop function.

[Note: the lqMiniTerm is evolving a bit and will continue to evolve for a while as we experiment and discover things that come up over and over that are easier to address in the mini terminal than in the main() file's code. Currently term_printf() is a candidate for becoming a miniterm feature. Find out why! :-) ]

There are two versions of snooper here, the (almost) original snooper and snooper-gui, which is mostly similar code but now runs in an lqMiniTerm loopFunc() and prints to a qt4 widget instead of stdout.

The code for both of thes apps is based more or less on code I found here but which has a few modifications.

The GUI version requires libLQ-qt and -DQT3_SUPPORT in the makefile.

Gottta tell yuh, I'm STILL not very impressed with QT's text editors. Slow, slow, slow. But we're going to go with this as another example of the lqMiniTerm, now running a snooper in it's loop_func().

There are several snips of interest, though the file set is too large to upload one by one, so we'll take a look at them out of context here.

The original lqMiniTerm (and this one) did not and does not have a 'printf()' like function to set text in the widget. So we created a C-like call that requires the object to be explicitely included in the parameter list.

[This applies generally to functions with variable args and TextEdit's of either flavor if you haven't done much of this kind of stuff.]

in snooper-gui.cpp
void term_printf(lqMiniTerm* term, const char* fmt, ...)
  char buf[4096];  
  bool prev_mode = text_mode;
  text_mode = true;
  va_start(args, fmt);
  vsnprintf(buf, 4096, fmt, args);
  // this appends a paragraph. we don't want that here
  // term->ui->plainTextEdit->appendPlainText(buf);
  // move to end and 'insert' instead. -DQT3_SUPPORT in makefile
  text_mode = prev_mode;
  term->last_pos = 
In order to make sure the function above acts exactly like printf() we have to 'insert' rather than 'append' to the text. The QString holding the text could be 'appended' and would not create a paragraph break, but the TextEdit will 'append' paragraphs, not just the text.

IF Qt gave us better access to the underlying QSTring we could probably speed this slug up quite a bit. Alas... Safety first. Their "safety", of course. They get fewer bug reports because running slow as a sea slug to prevent user errors is not technically a "bug". But QT3 TextEdit widgets were way faster. Three to ten times faster (and even more!), depending on what you were doing.

The point, however, is that if you move to the bottom of the text and insert new text there you won't get the redundant newlines.

Another point of interest is that the text edit will not automatically scroll to the position where you just inserted (appended) your text. That requires the "ensureCursorVisible()" call.

You can ignore the text_mode/prev_mode stuff. That's only for running it in interactive mode where the widget switches back and forth from input for a commandline and text output from some function. [That was done in the original lqMiniTerm experiment if you want to see it.]

Also in snooper-gui.cpp we have code to issue an error message if the user is not set as root.

Here's the error message.

OOPS!  Requires root permissions
Please close the window
By setting the "closing" flag, this blocks all further processing until the user closes the window. Here's the code.

// custom create
static bool term_create(lqMiniTerm* term)
  bool ok;
  inputsocket_create(pobj, 1000);
  ok = inputsocket_init(pobj, SOCK_PACKET, ETH_P_ALL);
  if(! ok)
    uid_t uid = getuid();
    if(uid != 0)
      term_printf(term, "OOPS!  Requires root permissions\n");
      term_printf(term, "ERROR: Failed to create socket.\n  %s\n", strerror(errno));
    term_printf(term, "Please close the window\n");
    term->closing = true;
    return ok = false;
  return ok = true;
That flag "term->closing" is important in the onClose() slot, which also attempts to NOT close if the user's code overrides it. It shuts down the run loop in any case.

Moving right along... in main() we use the libLQ-qt function lqStaysOnTop() and we change the wordwrap (which will come up often enough that we might want a simpler access to this property).

And as in the previous lqMiniTerm example here at the blog we call which performs the functions of qApp->exec() but allows us to run our loop_func every few milliseconds.

The code to set the timeout for the loop_func() is in lqminiterm.cpp. The default is 20 ms, which gives good response times for events in the widget. Long timeouts may make it seem like the button isn't responding.

Now for some more interesting stuff.

In the 'inc/' folder, which acts as a library of definitions for the loop_func (so we don't need to actually create and link to another actual lib) we create an experimental inputsocket_t object.

THIS IS SO WE CAN HIDE THE MESS ARPA MADE OF SOCKETS. That is, we can call misnamed functions and get them to work out of sight of the innocent and so that nobody gets confused by it.

And judging by the number of broken sockets programs I've seen, it seems that a quite a lot of people have been confused by it. If you are reading this, rest assured that you are not the only one. ;-)

So that's the reason for the socket objects. But we'll see whether to go the direction of netcat with huge objects, or if we can keep these relatively simple to handle just three or four cases as we go along, Computer Mad Science being what it is. ;-)

bool inputsocket_create(inputsocket_t* o, int datalen)
  bool ok;
    return ok = false;
  char* data = (char*)malloc(datalen);
    return ok = false;
  o->data = data;
  o->datalen = datalen;
  // load some defaults
  o->domain = PF_INET;
  o->flags = SOCK_NONBLOCK; // OR new flags with this
  return ok = true;      

// returns true on success
bool inputsocket_init(inputsocket_t * pobj, uint sock_flags, long type)
  bool ok;
  pobj->sid  = socket(pobj->domain, pobj->flags | sock_flags, htons(type));
  return ok = pobj->sid >= 0;
In the code above, we have a 'create' and 'init' function, similar to pthreads. The create function is called through the 'setup' code for the class. There's a matching destroy function to allow us to free the memory allocated above, of course. And it's called by the onClose() function in the class.

The defaults set can be overridden (PF_INET) or OR-ed (SOCK_NONBLOCK).

As we mentioned a while back, in a gui we can't let this loop block (waiting for connections or input) without adding a lot of extra code for a listener thread and a mutex. So we don't block. The SOCK_NONBLOCK flag acts like the O_NONBLOCK part of the following fcntl() call.
fcntl(socket_fd, F_SETFL, O_ASYNC | O_NONBLOCK)
A couple of final notes.

We also have a subdir named 'ui' for the gui library code. The gui was done with QT Designer (which works better than qt Creator for this kind of stuff.. hands-on stuff) and with additional functions and templates created with 'mc2 -create qt4-files' and the 'ui-tool' from the libLQ-qt-mc2 d/load.

[But the classes are written and the makefiles are done and so that's not why we need libLQ-qt to create this though modifying it is much easier with the libLQ-qt tools.]

And finally, this all boils down to organizing the sockets functions into three stages.
  • Setup,
  • Run (or "loop"), and
  • Cleanup.

Beginning middle and end, sorta like almost everything, and we have created our lqMiniTerm to support these three stages. So... It works! :-)

Ok, enough talk. Here's a screenshot of this thing running.

To continue to the self extractor which includes a server and client for testing the snooper(s) go here.
Posted in Uncategorized
Views 703 Comments 0
« Prev     Main     Next »
Total Comments 0




All times are GMT -5. The time now is 11:36 AM.

Main Menu
Write for LQ is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration