Hamachi and UDP Broadcast Games

May 28, 2009

I was recently trying to play some old game (Starcraft, Warcraft 3, and others) in LAN with some friends through the hamachi VPN system. All attempts were unsucessful due to the fact that the broadcasted UDP packet weren’t sent over the VPN interface but only in the local LAN.

To solve this we just had to manipulate the routing table of the systems.
After connecting to the hamachi VPN just do these commands as root user

OS X: as long hamachi uses 5.x.x.x for his nodes
route add -net 255.255.255.255 5.255.255.255

Linux: where ham0 is the hamachi interface
route add -net 255.255.255.255 netmask 255.255.255.255 dev ham0
No, this is not working, i tried to test it and to work around it but found no solution to host on a linux machine by now. If anybody knows how to do so, let me know

It seems to be working on gentoo (look at the comments)

This will redirect all the broadcast packets, maybe it can interfere with some other program, but as long as you want some time off to play it works great. To clear the modification to the routing table we didn’t do anything else then disconnecting from the hamachi VPN, the system handles the disappareance of the interface removing every involved route.

Resuming*

Game Linux MacOS
Warcraft 3 play host
Starcraft host host
Delta Force host untested

* Linux has no other setup then just starting hamachi. This all was tested between a Mac and a Linux systems

If someone can test other games and maybe help on the linux problem that would be great.

Hope this helps!
[last update 10 August 2009]


Convert Man pages to PDF

June 14, 2008

Always wanted to watch a man page in a pdf file? It is clearly needed sometimes, especially on mac, since it is the easiest way i know to print a man page or to read it not from a terminal.

The problem is solved easily for both Mac OS and linux. I had to add control for <code>pstopdf</code> too, since on mac it is called that way and has different parameters (but you may have <code>ps2pdf</code> installed with macports anyway).

#! /bin/bash

if [ $# -eq 1 ] ; then
    to_pdf=$(which ps2pdf)
    if [ -z "$to_pdf" ] ; then
        to_pdf=$(which pstopdf)
    fi

    name="$1"
    case "$to_pdf"  in
        *pstopdf) man -t "$name" | "$to_pdf" -i -o "$fname.pdf" ;;
        *ps2pdf)  man -t "$name" | "$to_pdf" - "$name.pdf" ;;
        *)        man -t "$name" > "$fname.ps"
    esac
    exit $?
fi
echo "Wrong number of parameters"
exit 1

Just call it like man2pdf gcc and you’ll get gcc.pdf


UPnP – Ruby Integration

June 8, 2008

[EDIT:This has been released as gem. check the code page]

At the moment i’m trying to create a ruby module to integrate some upnp functionality in the language.

I would like to do so to enhance the experience with rtorrent, a really nerdish torrent client. Ok, it uses curses, as interface, but it is just great, never crashed in 6 months and had a tiny memory footprint.
The idea is to connect to the local router and gather information about the port mappings and the data currently flowing in the local network and trough estimation change the upload rate.
Useful to use the bandwidth when it is unused, as long as i pay it i want to use it!  Here is how I have built such a module on Mac OS X 10.5.3 with the apple’s version of ruby (1.8). To avoid to write the code i’ll use the miniupnp (1.0) library and the utility swig (1.3.35)
The first is a upnp library which interacts with the IGDs (Internet Gateway Device) and the latter is an wrapper builder that will write all the glue code (C \iff Ruby) in my place.

Get miniupnp to compile

The first thing is to get the library to compile on my mac. The distribution makefile has some minor flaws, I have modified it to build the dynamic library with this patch makefile-osx.patch
--- a/Makefile
+++ b/Makefile
 HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
 upnpreplyparse.h upnperrors.h
 LIBRARY = libminiupnpc.a
-SHAREDLIBRARY = libminiupnpc.so
+SHAREDLIBRARY = libminiupnpc.dylib
 SONAME = $(SHAREDLIBRARY).$(APIVERSION)
 EXECUTABLES = upnpc-static upnpc-shared \
 testminixml minixmlvalid testupnpreplyparse
@@ -83,7 +83,7 @@ $(LIBRARY):	$(LIBOBJS)
 $(AR) crs $@ $?

 $(SHAREDLIBRARY):	$(LIBOBJS)
-	$(CC) -shared -Wl,-soname,$(SONAME) -o $@ $^
+	$(CC) -dynamiclib -o $@ $^

 upnpc-static:	upnpc.o $(LIBRARY)
 $(CC) -o $@ $^
As the build completes everything is almost done. Another patch has to be applied to avoid a swig warning for a memory leak (miniupnp.g-memleak.patch).
--- a/miniupnpc.h
+++ b/miniupnpc.h
@@ -16,7 +16,7 @@ extern "C" {
 #endif

 /* Structures definitions : */
-struct UPNParg { const char * elt; const char * val; };
+struct UPNParg { char * elt; char * val; };

 int simpleUPnPcommand(int, const char *, const char *,
 const char *, struct UPNParg *,

Get Glue Code

Then we have to write a swig interface file, describing what should be put in the ruby module writing this in the file upnp.i
%module miniupnp
%{
#include "miniupnpc.h"
%}

%include "cpointer.i"
%pointer_functions(unsigned int, uintp);

%import declspec.h
%include miniupnpc.h
%include upnpcommands.h
%include igd_desc_parse.h

Make the Module

This will create a module that will contain all the functions from miniupnpc.h, upnpcommands.h and igd_desc_parse.h and a struct i have added to ease the use of the library. Swig is then called

swig -ruby upnp.i
gcc -fPIC upnp_wrap.c -c -o upnp_wrap.o -I/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0/

Generating the file upnp_wrap.c glue code which must be compiled with the ruby includes. From this point there is a decision to take, if the miniupnp library is to be linked to the module as an external shared library or be included in it as static code.
To link it dynamically

gcc -fPIC -bundle -undefined dynamic_lookup upnp_wrap.o -o miniupnp.bundle -lruby -lminiupnpc -L<miniupnpc install path>

And to link it statically

gcc -fPIC -bundle -undefined dynamic_lookup upnp_wrap.o -o miniupnp.bundle -lruby miniwget.o minixml.o igd_desc_parse.o minisoap.o miniupnpc.o upnpreplyparse.o upnpcommands.o minissdpc.o upnperrors.o

Test it

Now is time to use the newly created module. This can be done in 2 ways too. Installing it in the ruby library path or configuring the library path.


# system install
cp miniupnp.bundle /Library/Ruby/Site/1.8/
# setup path, bundle_path is where the
# bundle is (for instance $PWD)
export RUBYLIB=bundle_path

Here there is a little script to test that everything is working
# The feature name begins with a lowercase letter...
require 'miniupnp'

# max time to wait for the upnp devices
MAX_WAIT_TIME = 1000

# discover upnp
list = Miniupnp.upnpDiscover(MAX_WAIT_TIME,nil,nil)
if list == nil then
    puts "No UPNP device found"
    exit 1
end
puts "URL : #{list.descURL}"

# get valid internet gateway device
urls  = Miniupnp::UPNPUrls.new
datas = Miniupnp::IGDdatas.new
lan = ""*16
r = Miniupnp.UPNP_GetValidIGD(list,urls,datas,lan,16)
case r
when 0
    puts "No IGD found"
    exit 2
when 1
    puts "A valid connected IGD has been found"
when 2
    puts "A valid IGD has been found but it is reported as not connected"
when 3
    puts "An UPnP device has been found but was not recognized as an IGD"
    exit 3
end

puts "Client LAN IP: #{lan}"
ext=""*16
r = Miniupnp.UPNP_GetExternalIPAddress(urls.controlURL,datas.servicetype,ext)
if r == 0 then
    puts "External IP: #{ext}"
else
    puts "Error while retriving the external ip address"
end

# print urls
puts "*** urls"
puts "controlURL: #{urls.controlURL}"
puts "ipcondescURL: #{urls.ipcondescURL}"
puts "controlURL_CIF: #{urls.controlURL_CIF}"

# print datas
puts "*** datas"
puts "cureltname: #{datas.cureltname}"
puts "urlbase: #{datas.urlbase}"
puts "level: #{datas.level}"
puts "state: #{datas.state}"
puts "controlurl_CIF: #{datas.controlurl_CIF}"
puts "eventsuburl_CIF: #{datas.eventsuburl_CIF}"
puts "scpdurl_CIF: #{datas.scpdurl_CIF}"
puts "servicetype_CIF: #{datas.servicetype_CIF}"
puts "devicetype_CIF: #{datas.devicetype_CIF}"
puts "controlurl: #{datas.controlurl}"
puts "eventsuburl: #{datas.eventsuburl}"
puts "scpdurl: #{datas.scpdurl}"
puts "servicetype: #{datas.servicetype}"
puts "devicetype: #{datas.devicetype}"

puts "Get maximum bandwith"
up=Miniupnp.new_uintp()
down=Miniupnp.new_uintp()
Miniupnp.UPNP_GetLinkLayerMaxBitRates(urls.controlURL_CIF,datas.servicetype_CIF,down,up)
puts "up: #{Miniupnp.uintp_value(up)} down: #{Miniupnp.uintp_value(down)}"
Miniupnp.delete_uintp(up)
Miniupnp.delete_uintp(down)

# release memory
Miniupnp.freeUPNPDevlist(list)
Miniupnp.FreeUPNPUrls(urls)
I can’t get wordpress to display correctly the content of lan and ext variables, it should be “” repeated 16 times. The result should be something like this
URL : http://192.168.0.1:49152/gateway.xml
A valid connected IGD has been found
Client LAN IP: 192.168.0.100
External IP: ***.***.***.243
*** urls
controlURL: http://192.168.0.1:49152/upnp/control/WANIPConnection
ipcondescURL: http://192.168.0.1:49152/ipcfg.xml
controlURL_CIF: http://192.168.0.1:49152/upnp/control/
WANCommonInterfaceConfig
*** datas
cureltname: presentationURL
urlbase: http://192.168.0.1:49152
level: 0
state: 3
controlurl_CIF: /upnp/control/WANCommonInterfaceConfig
eventsuburl_CIF: /upnp/event/WANCommonInterfaceConfig
scpdurl_CIF: /cmnicfg.xml
servicetype_CIF: urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
devicetype_CIF: urn:schemas-upnp-org:device:WANDevice:1wayDevice:1
controlurl: /upnp/control/WANIPConnection
eventsuburl: /upnp/event/WANIPConnection
scpdurl: /ipcfg.xml
servicetype: urn:schemas-upnp-org:service:WANIPConnection:1
devicetype: urn:schemas-upnp-org:device:WANConnectionDevice:1

Maximum bandwith
up: 352000
down: 2464000

This is just a start, I’ll make more testing and i’ll make sure it works. There may be some more things to add to upnp.i

Full code can be found in the code page
Edit 15-06-08: Module name changed to miniupnp from upnp

[Continued by: UPnP Wrapper]
[EDIT:This has been released as gem. check the code page]