Non-blocking IO::Socket::SSL client example


use IO::Socket::INET;
use IO::Socket::SSL;
use IO::Select;
use strict;

my $sock = IO::Socket::INET->new(
  PeerHost => 'encrypted.google.com', PeerPort => 443, Blocking => 0
) or die $@; # first create simple N-B socket with IO::Socket::INET

my $sel = IO::Select->new($sock); # wait until it connected
if ($sel->can_write) {
    print "IO::Socket::INET connected\n";
}

# upgrade socket to IO::Socket::SSL
IO::Socket::SSL->start_SSL($sock, SSL_startHandshake => 0);

# make non-blocking SSL handshake
while (1) {
    if ($sock->connect_SSL) { # will not block
        print "IO::Socket::SSL connected\n";
        last;
    }
    else { # handshake still incomplete
        print "IO::Socket::SSL not connected yet\n";
        if ($SSL_ERROR == SSL_WANT_READ) {
            $sel->can_read;
        }
        elsif ($SSL_ERROR == SSL_WANT_WRITE) {
            $sel->can_write;
        }
        else {
            die "IO::Socket::SSL unknown error: ", $SSL_ERROR;
        }
    }
}

# sucessfully connected, we can write to socket
$sock->syswrite(
    join(
        "\015\012",
        "GET / HTTP/1.0",
        "\015\012"
    )
) or die $!;

# and then read from it
while ($sel->can_read && $sock->sysread(my $buf, 1024)) {
    print $buf;
}

$sock->close();

OSS emulation with ALSA

I faced out with this problem when tried to play Postal 2 on my debian PC. There was no sound and in the console I could see such error:

open /dev/[sound/]dsp: No such file or directory

Google said that aoss from alsa-oss package could help me ... but not on 64 bit system, because Postal 2 is 32 bit app. Ok, 32 bit app should work with 32 bit aoss. And as practice has shown it works. Go to packages.debian.org and download alsa-oss package for i386, then install it with

dpkg -i --force-architecture alsa-oss_VERSION_i386.deb

Now you could start the game with

aoss postal2

Notice: this is ugly hack, good practice says that you should make new amd64 package with 32 bit contents with name different from alsa-oss to avoid conflicts with original alsa-oss package.

PyQt and QImage.scanLine()

As we can see from the documentation QImage.scanLine() returns sip.voidptr object. But how to get pixels colors from this object? Reading sip documentation tells us that it has asstring(length) method, which returns length bytes from sip.voidptr position. Ok, that's enough to get colors pixel by pixel. Let's see an example:
import struct;
from PyQt4 import QtGui;

# get QImage object
# ...
#
img = img.convertToFormat(QtGui.QImage.Format_RGB32);
width = img.width();
height = img.height();

linebytes = width * 4;
for y in xrange(0, height):
 pixels = img.scanLine(y).asstring(linebytes);
 for x in xrange(0, width):
  # unpack 32 bit integer
  color = struct.unpack('I', pixels[x*4:x*4+4])[0];
  # here it is
  r = QtGui.qRed(color);
  g = QtGui.qGreen(color);
  b = QtGui.qBlue(color);
 

Three ways to work with LWP via socks

LWP::Protocol::socks

This module allows to specify socks for LWP in the same way as you could specify http proxy, which LWP supports out-of-the-box. The problem of this module is that it is only supports socks version 5. But as we can see 4 version is still in use in the real world. To fix this problem I posted a patch on the cpan. Make sure that IO::Socket::Socks 0.2 or higher installed, because only in this version I added support for 4 version of the protocol. May be in the next few years author will accept the patch, but now if you want to use socks 4 you should patch the module yourself.

Here is a simple example of usage:

use LWP;
# You shouldn't say `use LWP::Protocol::socks'
# However you could do it to make sure it is installed
# If it is installed then it will be loaded automatically when needed
# But if it is not then the request will fail

# create lwp object as usual
my $lwp = LWP::UserAgent->new();
# and set socks 5 proxy with host=localhost and port=1080
$lwp->proxy(['http', 'https'], 'socks://localhost:1080');
# use 'socks://login:password@localhost:1080' instead if you
# need authentication
# ...
# thus you could set socks 4 proxy
# if module supports it
$lwp->proxy(['http', 'https'], 'socks4://localhost:1080');
# use 'socks://userid:@localhost:1080' instead if you need
# to specify user id for IDENT

Benefits of using LWP::Protocol::socks

  • Easy and logical proxy configuration, in the same way as you usual do it with LWP
  • Ability to setup different proxy for different objects
  • Authentication with login and password support
  • HTTPS support
  • Stable and supported IO::Socket::Socks module as backend

Cons of using LWP::Protocol::socks

  • No socks4 support out-of-the-box

IO::Socket::Socks::Wrapper

In fact this module allows to get worked via socks any pure perl module. To be more accurate - any connection initiated by perl connect() function. As it uses IO::Socket::Socks as backend it supports both 4 and 5 socks version. This module could be used to wrap any network connection or connections from separate modules. Because we talking about LWP let's wrap it up:

use IO::Socket::Socks::Wrapper (
	# wrap classes used by LWP for http and https connections
	Net::HTTP => {
		ProxyAddr => 'localhost',
		ProxyPort => 1080,
		SocksVersion => 4
	},
	Net::HTTPS => { # works since IO::Socket::Socks::Wrapper 0.02
		ProxyAddr => 'localhost',
		ProxyPort => 1080,
		SocksVersion => 4
	}
);
use LWP;

# then use LWP as usual
my $lwp = LWP::UserAgent->new();
# all connections will be done via specified socks proxy
my $resp = $lwp->get('http://www.google.com/');
print $resp->status_line, "\n";

$resp = $lwp->get('https://encrypted.google.com/');
print $resp->status_line, "\n"; 

Benefits of using IO::Socket::Socks::Wrapper

  • Universal solution: wrap up any module in the same way
  • It supports any options supported by IO::Socket::Socks

Cons of using IO::Socket::Socks::Wrapper

  • Global wrapping: you can't specify different proxy for different LWP objects

LWP::Protocol::http::SocksChain

This is extension to LWP::Protocol. It uses Net::SC as backend. From the documentation: Net::SC - perl module for create the chain from the SOCKS/HTTP proxies. So, this extension to the LWP::Protocol also could create connections via socks chain. It supports 4 and 5 socks versions. Let's see an example:

use LWP::Protocol::http::SocksChain;
use LWP::Protocol::https::SocksChain;
use LWP;

# turn on proxy chain
LWP::Protocol::implementor(http => 'LWP::Protocol::http::SocksChain');
LWP::Protocol::implementor(https => 'LWP::Protocol::https::SocksChain');

# setup proxy chain
@LWP::Protocol::http::SocksChain::EXTRA_SOCK_OPTS = (
	Chain_Len       => 1,
	Debug           => 0,
	# format: host:port:uid:pswd:socks_ver
	Chain_File_Data => ['localhost:1080:::5'],
);
@LWP::Protocol::https::SocksChain::EXTRA_SOCK_OPTS = (
	Chain_Len       => 1,
	Debug           => 0,
	Chain_File_Data => ['localhost:1080:::5'],
);

# then use LWP as usual
my $lwp = LWP::UserAgent->new();
# all connections will be done via specified socks proxy
# ...

Benefits of using LWP::Protocol::http::SocksChain

  • Allows to create connections via socks chain

Cons of using LWP::Protocol::http::SocksChain

  • Looks like ugly hack


Conclusion:

All of this three modules have roughly equal opportunities. All three supports socks 5 and 4 version (first with a patch) and authorization with login and password. The first two uses IO::Socket::Socks as backend, third uses own backend, called Net::SC.

LWP::Protocol::socks is the most simple and logical way to include socks support in the LWP. IO::Socket::Socks::Wrapper is the most universal solution if you need to include socks support everywhere. LWP::Protocol::http::SocksChain is unique solution for creating connections via socks chains.

Read original modules documentation to get more information.