Archive for the 'Code and Cruft' Category

Qt: Improving QGraphicsView Performance

Saturday, February 3rd, 2007

I recently wrote a Qt-based application in C++ that relies heavily on the QGraphicsView framework that made its first public appearance in Qt 4.2. QGraphicsView has been the target of some criticism for poor performance. I am a long-time user of Qt3’s QCanvas class which served me very well, in performance terms, but that lacked several features that made it both difficult to use and less pretty. Namely, it had poor support for mouse handling and item selection, and it had no support for anti-aliasing or alpha-level transparency. The one thing it did have, however, was speed, blazing fast speed. I could throw hundreds of QCanvasItems on the screen with no apparent slow down. Blazing speed.

Then along came QGraphicsView, which promised to be every bit as fast as QCanvas, but with a much more intuitive mouse handling, item selection, and animation API. It’s true, the QGraphicsView is miles ahead of QCanvas in that regard. You basically get all that stuff for free. It even sports multi-select using both meta keys and a rubber band, all built in. It’s fantastic. What QGraphicsView doesn’t provide, however, is speed. Over the past few months I’ve found a couple tricks that speed things up a bit. Read on for three tips that have helped me improve QGraphicsView performance.

(more…)

Using Xerces-C++ Progressive Scan with Qt

Sunday, November 12th, 2006

Parsing XML is fun again with Xerces progressive scan.

Do you have large XML files that you need to parse in your GUI application? Are you sick of your XML parser blocking the event loop while it laboriously parses all that XML? Don’t waste another day! Xerces-C++ progressive scan was made for you, my friend.
(more…)

Setting up a SOCKS server with SSH

Thursday, July 27th, 2006

Does your firewall block port 25 so you can't use Thunderbird to send email? Do you have a Linux box on the open Internet? If so, you are in luck.

I run Windows on my desktop, and I have a Linode machine that runs my email server. When I discovered that I was behind a firewall that blocked port 25, I was bummed that I couldn't send email via Thunderbird.

SOCKS to the rescue!

By setting up a SOCKS server with SSH, you can encrypt all out-bound email on your desktop, tunnel it to your Linux box, where it is decrypted and sent to its destination. Here's how you do it:

On your Windows box, open Cygwin and run

CODE:
  1. ssh user@mylinuxbox.com -D 1234

Once the command runs, it will put you in a normal SSH console session. Just minimize the window and leave it like that.

Then, open Thunderbird and click Tools -> Options -> Connection Settings. Enter localhost for the SOCKS Host and 1234 for the Port. Tick the "SOCKS v5" radio button, and you are good to go. Now, all email that Thunderbird sends will be SSH-encrypted between your desktop and your Linux box and you can send email again despite the firewall blocking port 25.

If you get really fancy, you can install your public key in your Linux box's .ssh/authorized_keys file and then you won't even have to enter a password. Then, create a shortcut in Windows like this:

CODE:
  1. C:\cygwin\ssh.exe user@mylinuxbox.com -D 1234

And put it in the Start Menu under the Startup folder, and your SOCKS server will automagically start every time you login to Windows.

The other cool thing you can do now that you have a SOCKS server running is tunnel all your web traffic through it in Firefox. Just configure Firefox to use localhost as its SOCKS server and no one on your LAN will be able to see what you are surfing, since it will just look like encrypted SSH traffic to and from mylinuxbox.com.

Of course you'll have to replace mylinuxbox.com with your actual Linux box's host name.

Enjoy!

(edited on April 23, 2007 to fix two incorrect host settings)

Bash socket programming with /dev/tcp

Tuesday, May 23rd, 2006

Today I discovered a nifty way to do socket programming in bash without the need for netcat (nc) or telnet: /dev/tcp. Say you want to connect to Google and fetch their front page. Just do this:

CODE:
  1. exec 3<>/dev/tcp/www.google.com/80
  2. echo -e "GET / HTTP/1.1\n\n">&3
  3. cat <&3

I found this very handy when trying to connect to a host and read some info from a socket, but I wanted to do it all in a few lines of bash. This is great, because you don't have to worry about what version of Python or Perl your users will have. If they've got bash, you're set. There is one caveat: some systems (Debian included) don't enable /dev/tcp. I don't know why, but they don't. So make sure your target system has it before coding this up. Oh, and you can use /dev/udp too if you really want to spice things up!

Where does this come from? It turns out it's a pure bashism, which has to be enabled when you compile bash. Bash actually intercepts "/dev/tcp" and provides special behavior, so you're not actually opening a device node called /dev/tcp. Pretty cool, eh?!

Happy bashing!

PHP: The @ Operator

Sunday, May 7th, 2006

I've seen some confusion online lately about the purpose of the "@" operator in PHP. Let's figure out exactly what the "at operator" does.

PHP holds your hand with error reporting during development by printing error messages to the user's browser automatically when something goes wrong. This often looks something like this:

Warning: mysql_connect() [function.mysql-connect]: Unknown MySQL server host 'woopsy.example.com' (1) in errors.php on line 3

The code that created this warning looks like this:

PHP:
  1. mysql_connect( "woopsy.example.com" );

Pretty simple -- I tried to connect to a non-existent MySQL server using a mistaken hostname. This is handy, but I usually don't like these kinds of errors to show up when a user browses my site. We can make the error go away by prepending a "@" on the front of the call to mysql_connect(), like this:

PHP:
  1. @mysql_connect( "woopsy.example.com" );

This gets rid of the warning message we saw earlier, but now we have no way of knowing whether mysql_connect() was actually able to connect or not. To fix that, we need to check the return value. According to the mysql_connect() documentation, the function returns a MySQL link identifier on success and FALSE on failure. So, let's do this:

PHP:
  1. $db = @mysql_connect( "woopsy.example.com" );
  2. if( $db === false )
  3. {
  4.    echo "Could not connect to server.";
  5.    exit();
  6. }

The lesson to take away from this is that the "@" operator suppresses error messages, not return values. You can read more about the operator at the PHP Error Control Operator documentation page.

For the motivated reader, the "@" operatore has many more applications. You can use it to suppress errors in include files and even bad array indexes.

The best way to deal with errors, however, is to use your own error handling function by calling set_error_handler() . This way, you can get notified whenever an error occurs, and you can even be told the error number, message, file, and line number. This way you can log it or even present a link for users to report the bug. It's very handy, and a great way to find and fix bugs without requiring too much user inconvenience.

The phpLDAPadmin project has an excellent implementation of an error handler, which can be viewed here. Search that page for pla_error_handler. It reports lots of versions (ie, the web server and PHP version), the exact error message, and even some PHP settings. It proved very useful for users to report bugs, since they could just copy/paste the output on the SourceForge bug tracker. '

This leads me to my final comment. I've already mentioned that the best way to handle errors in PHP is to implement your own error handler and call set_error_handler(). In this function, you should log all errors, and then only display a message for those that happen without the "@" operator present. In other words, you should do something like this:

PHP:
  1. function my_error_handler( $errno, $errstr, $file, $lineno )
  2. {
  3.    my_log_msg( "Error $errno: $errstr in file $file on line $lineno" );
  4.  
  5.    if( 0 == ini_get( "error_reporting" ) || 0 == error_reporting() )
  6.       return;
  7.  
  8.    // Display an error message of some kind
  9. }

Any now my final comment: I use error_reporting() in all my PHP applications to set the strictest error reporting possible like so:

PHP:
  1. error_reporting( E_STRICT );

You may not want such strict error reporting in your application, so choose from the available error levels. This will give you all kinds of error messages, but it will help you bullet-proof your code in a jiffy.

Enjoy your error reporting!

SpeedScheduler featured on Digg (sort of)

Tuesday, May 2nd, 2006

SpeedScheduler, a little Azureus plugin that I wrote a while back, was featured in an article that made Digg's front page: Top Azureus Plugins Revealed. Scroll to the bottom of the article for a few screenshots and a little write up. That's pretty nifty.

Qt: More slots please

Tuesday, March 28th, 2006

I'm usually an avid fanboy of Qt, but the more I use it, the more I find myself wanting two changes:

1. More slots please
2. More control over signals 

Read on for a couple examples.

(more...)

Make and the ?= operator

Tuesday, January 10th, 2006

The GNU crew improved Make with lots of handy stuff. One such gem that I found today is the ?= operator, which only defines a macro if it is not already defined (like as an environment variable). It behaves almost like wrapping the assignment in ifndef. John Gramm-Cunning has a good explanation of this subtle difference.

Here's an example of ?= in action.

CODE:
  1. INSTALL_HOST ?= root@myhost.example.com

The INSTALL_HOST macro will have the value "root@myhost.example.com" unless someone specifies it as an environment variable when invoking make. This makes its value easily overridable by users calling your Makfile, like this:

CODE:
  1. $ INSTALL_HOST=root@foobar.com make install

I find it pretty handy.

However, I have one gripe. Make in general is tough to learn because its keywords and operators are not Googlable. Say I find the ?= operator in a Makefile and I want to look it up. Normally, I would just punch it into Google, but that just gives you a bunch of junk results. Not a huge deal, but it's tough to find good docs out there for this reason

Nobody knows what f_fsid is supposed to contain

Thursday, January 5th, 2006

It's not everyday that a man page makes you laugh out loud, but this blurb from the page for statfs did the job for me:

CODE:
  1. Nobody knows what f_fsid is supposed to contain

I really did laugh out loud, until I read below in the page that basically explains that f_fsid just holds different things on different operating systems.

Good for a laugh nonetheless.

Python: Uptime script

Saturday, November 19th, 2005

I've been writing Python for a grand total of 2 days. I recently wrote a little Python script to print a Linx or UNIX system's uptime. This took about 10 minutes to write, so I was pretty pleased. It even runs well on a 75MHz Busybox embedded Linux system. Check it out:

PYTHON:
  1. #!/usr/bin/python
  2. import os
  3.  
  4. #----------------------------------------
  5. # Gives a human-readable uptime string
  6. def uptime():
  7.  
  8.      try:
  9.          f = open( "/proc/uptime" )
  10.          contents = f.read().split()
  11.          f.close()
  12.      except:
  13.         return "Cannot open uptime file: /proc/uptime"
  14.  
  15.      total_seconds = float(contents[0])
  16.  
  17.      # Helper vars:
  18.      MINUTE  = 60
  19.      HOUR    = MINUTE * 60
  20.      DAY     = HOUR * 24
  21.  
  22.      # Get the days, hours, etc:
  23.      days    = int( total_seconds / DAY )
  24.      hours   = int( ( total_seconds % DAY ) / HOUR )
  25.      minutes = int( ( total_seconds % HOUR ) / MINUTE )
  26.      seconds = int( total_seconds % MINUTE )
  27.  
  28.      # Build up the pretty string (like this: "N days, N hours, N minutes, N seconds")
  29.      string = ""
  30.      if days> 0:
  31.          string += str(days) + " " + (days == 1 and "day" or "days" ) + ", "
  32.      if len(string)> 0 or hours> 0:
  33.          string += str(hours) + " " + (hours == 1 and "hour" or "hours" ) + ", "
  34.      if len(string)> 0 or minutes> 0:
  35.          string += str(minutes) + " " + (minutes == 1 and "minute" or "minutes" ) + ", "
  36.      string += str(seconds) + " " + (seconds == 1 and "second" or "seconds" )
  37.  
  38.      return string;
  39.  
  40. print "The system uptime is:", uptime()

One interesting thing about this script is its emulation of the C ternary operator using Python's short-circuited "and" operator. Notice this bit:

PYTHON:
  1. (days == 1 and "day" or "days" )

Python doesn't have the C-style ternary operator:

C++:
  1. (days == 1 ? "day" : "days")

So the short-circuited "and" is a decent alternative. Instead of ignorantly printing "1 days", this code will actually print "1 day" and "2 days" like it should.