4 · 02

Exploiter le SIP de sa Freebox

J'ai commencé à jouer récemment avec le compte SIP de ma Freebox.

Le compte SIP se paramètre via le panel de gestion de Free, dans l'onglet Téléphonie. Deux options sont possibles:

  1. Rediriger les appels vers la Freebox
  2. Rediriger les appels vers le serveur SIP

Dans le deuxieme cas, il vous faudra un téléphone IP si voulez conserver un téléphone physique connecté à la Freebox. Pour ma part, ayant un téléphone analogique standard, je redirige les appels vers la Freebox. J'utilise donc le serveur SIP uniquement pour passer des appels, et non en recevoir.

Il existe de nombreux clients SIP. J'utilise Linphone sur Linux que je trouve léger et stable.

Un point interessant, le serveur SIP est accessible de l'exterieur, autrement dit, vous pouvez appeler en illimités sur des fixes en France et dans certains pays depuis n'importe où en utilisant votre compte SIP Freephonie.

De plus, si vous êtes l'heureux possesseur d'un iPhone (ou tout autre téléphone sur Symbian, Windows Mobile ou Android), il vous suffit d'installer un client SIP (j'utilise iSipSimple sur iPhone) et de solliciter votre forfait data illimité (ou pas) pour passer vos appels vers les fixes tout en utilisant votre généreux forfait Free.

Attention aux appels vers les mobiles qui ne seraient pas avantageux.

6 · 01

How to auto-update Chromium on Mac OS X, Linux and other

I want to try to use Chromium as my first web browser. But for the moment, Chromium suffers from a lack of package maintaining though it targets developers. On my Gentoo Linux, I let portage to handle my Chromium version. But I also use Mac OS X at work, so I have written a little shell script to auto update my Chromium.app. Put the content of this scripts wherever you want and make it executable ($> chmod 755 chromium_update.sh).
#!/bin/sh
# Chromium update script
# - by shad <shad@zaphod.eu>
# mac | linux | ...
OS=mac
LATEST=$(wget -q -O - http://build.chromium.org/buildbot/snapshots/chromium-rel-${OS}/LATEST)
INSTALL_DIR=/Applications
TMP="/tmp/update-chrome-$RANDOM"
(
mkdir $TMP ; cd $TMP
echo Download...
wget -q -O chrome.zip http://build.chromium.org/buildbot/snapshots/chromium-rel-${OS}/${LATEST}/chrome-${OS}.zip
if [ $? -ne 0 ] ; then
echo Cannot update.
exit 1
fi
echo Unzip...
unzip -qq chrome.zip
echo Copying...
rm -rf "${INSTALL_DIR}/Chromium.app"
mv chrome-$OS/Chromium.app "$INSTALL_DIR"
)
rm -rf $TMP
Then, set a crontab rule to choose the update interval ($> crontab -e). Mine runs every day at 12:00.
# Run Chromium update script every day at 12:00
00 12 * * * /Users/shad/mbin/chromium_update.sh
I hope it will be useful for someone as much as for me.
30 · 10

CirruxCache: speeds up your HTTP app using Google Appengine as a CDN

It is a great moment, for the first time since I have started to work at Zoomorama, I have just released as open-source an important part of our server platform.

I previously explained how to use Google AppEngine as a Content Delivery Network (CDN). CirruxCache project concretizes this idea. I released the first version based as the one we use in production.

Here is the features it currently supports:

  • honor Cache-Control
  • cache TTL override
  • several POP (Point Of Presence) configuration mapped on custom base-url
  • ignore query string
  • POST forwarding
  • expired entries garbage collection
  • extensibility


CirruxCache is not documented at the moment even if you would be able to use it after reading the comments in the app.py file. I'll document this app in the next few days, but if you need more documentation, don't hesitate to contact me.

The project website.

30 · 07

Speed up HTTP delivering using Google AppEngine

Google AppEngine provides an high-level cloud service which means that your application will be distributed automatically on top of the Google platform. All of your code will depends on the AppEngine SDK, so it could be risky to develop complex application on it. I develop a webservice application for content delivering and content publishing at Zoomorama. We currently use Akamai CDN as a simple cache layer to improve data delivering accross the world. It is interesting for me to use AppEngine in the same way: without changing anything on my existing code base. I have found some posts on blogs dealing with this AppEngine usage, but they are not focused on dynamic HTTP caching like a real CDN. Principle is very simple, all HTTP requests on my AppEngine application will be copied to the AppEngine Datastore. Moreover data which are delivered through AppEngine are cached by AppEngine servers. The code below is a tiny proof of concept:
# HTTP caching on Google App Engine
# - by shad <shad@zaphod.eu>
#

import web # webpy 0.3x
from google.appengine.ext import db
from google.appengine.api import urlfetch

origin = 'http://my.website.com'

urls = (
'(/.*)', 'Root'
)

class Cache(db.Model):
data = db.BlobProperty(default=None)
headers = db.ListProperty(str)

class Root(object):
def GET(self, request):
cache = self.readCache(request)
if cache is None:
cache = self.writeCache(request)
for h in cache.headers:
print h
return cache.data

def readCache(self, key):
cache = cache = Cache.get_by_key_name(key)
if cache:
return cache

def writeCache(self, request):
url = origin + request
response = urlfetch.Fetch(url=url)
if response.status_code != 200:
raise web.NotFound()
cache = Cache(key_name=request)
cache.data = db.Blob(response.content)
cache.headers = []
for k, v in response.headers.iteritems():
cache.headers.append('%s: %s' % (k, v))
cache.put()
return cache

if __name__ == '__main__'
app = web.application(urls, globals())
app.cgirun()
I use webpy to depends on the AppEngine SDK as less as possible.
I have almost finished the production version of this application. I am doing some performance tests. This application is closed source for now. But I am going to release the code source in few weeks. This version will include:
  • Fetch from Memcache (about 10 times faster).
  • Headers forwarding.
  • Read "Cache-Control" and "Expires" to define a TTL (rfc 2616).
  • Multi origins (according to url mount points).
  • Other small features (force TTL, ignore query string, etc...).
It is important to note that AppEngine does not keep running instances of your application (your CGI is distributed and it is executed on demand). So this application have to start very quickly (no configuration file, no dynamic generation, etc...).
1 · 07

Generates your C++ bindings easily with SWIG

Today, I have to develop a client library. This client library aims to allow users to use my storage webservice app more easily. Mainly to avoid them to read my HTTP Rest API documentation. I want to target the most used languages, and of course, I don't want to develop the same library for each languages. The main reason is that my client library is a draft for the moment, and I want to make changes on the client API over the time. This library is very high level, so I take only the HTTP core class for the example:
#ifndef __HTTP_H__
#define __HTTP_H__

#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <exception>

#include <curl/curl.h>

namespace HTTP
{
class Error : public std::exception
{
private:
std::string _message;

public:
Error(const std::string &msg) : _message("HTTPError: ")
{
_message.append(msg);
}
virtual const char* what() const throw()
{
return _message.c_str();
}
virtual ~Error() throw() {}
};

class Response
{
private:
friend class Request;
std::map<std::string, std::string> _headers;
std::string  _version;
std::string  _code;
std::string  _message;
std::string  _body;

void  _parseHeaderLine(const std::string &headerData);
Response() {}

public:
const std::map<std::string, std::string> &getHeaders() const { return _headers; }
const std::string  &getVersion() const { return _version; }
const std::string  &getCode() const { return _code; }
const std::string  &getMessage() const { return _message; }
const std::string  &getBody() const { return _body; }
friend std::ostream&  operator<<(std::ostream &out, const Response &resp)
{
std::map<std::string, std::string>::const_iterator it, ite = resp._headers.end();
for (it = resp._headers.begin(); it != ite; ++it)
out << it->first << ": " << it->second << std::endl;
return out;
}
};

class Request
{
private:
std::string      _host;
unsigned int    _port;
CURL        *_curl;
struct curl_slist  *_headerList;
Response      _response;
std::ofstream    _outFile;
std::ifstream    _inFile;
std::string      _credentials;
std::vector<char>  _buffer;

void  _request(const std::string &uri);

public:
Request(const std::string &host, const unsigned int port = 80);
virtual ~Request();

virtual void  setHeader(const std::string &name, const std::string &value);
virtual void  setCredentials(const std::string &login, const std::string &passwd);
virtual void  get(const std::string &uri, const std::string &outFile = "");
virtual void  post(const std::string &uri, const std::string &data);
virtual void  postFile(const std::string &uri, const std::string &inFile);
virtual void  setVerbose();
virtual void  setHost(const std::string &host, const unsigned int port = 80);
static size_t  writeHeaderCallback(void *ptr, size_t size, size_t nmemb, void *stream);
static size_t  writeCallback(void *ptr, size_t size, size_t nmemb, void *stream);
static size_t  readCallback(void *ptr, size_t size, size_t nmemb, void *stream);
virtual const Response  &getResponse() const { return _response; }
};
}

#endif /* !__HTTP_H__ */
SWIG uses interface files to parse and to generate bindings. IMHO, a good thing is to have an only one interface file to add language bindings much easier.
Here is some documentation on SWIG interface syntax. First, here is my interface file (http.i):
%module http

%include stl.i
%include exception.i

%exception
{
try
{
$function
}
catch (std::exception &e)
{
SWIG_exception(SWIG_RuntimeError, e.what());
}
catch (...)
{
SWIG_exception(SWIG_RuntimeError, "Unknown exception");
}
}

%include "http.h"
%{
#include "http.h"
%}
All C++ code between %{ ... }% tags will be copied during generation. SWIG provides a lot of interface files. Some of them are language-dependant. So I have written a generic exception handler to use the same interface file for all targetted languages.
Finally, I just have to write a shell script to build each languages with the same http.i:
#!/bin/sh

CFLAGS_python_Darwin=-I/usr/include/python2.5
LDFLAGS_python_Darwin="-dynamiclib -lpython2.5 -o _zws.so"

CFLAGS_java_Darwin=-I/System/Library/Frameworks/JavaVM.framework/Headers
LDFLAGS_java_Darwin="-dynamiclib -o libzws.dylib"

CFLAGS_ruby_Darwin=-I/System/Library/Frameworks/Ruby.framework/Headers
LDFLAGS_ruby_Darwin="-dynamiclib -lruby -o zws.bundle"

CFLAGS_php_Darwin="$(php-config --includes)"
LDFLAGS_php_Darwin="-bundle -o zws.so"

if [ $# -lt 1 ] ; then
echo Usage $0 language
exit 1
fi

LANG=$1
ROOT=$(dirname $0)
OSNAME=$(uname -s)
ARCH=$(uname -p)

# All the source files
SRC="http.cpp"

(
DIR=${LANG}_${OSNAME}_${ARCH}
rm -rf ${DIR}/*
mkdir -p ${ROOT}/${DIR}
cd ${ROOT}/${DIR}

# This options will be always added to the compilation/linking
CFLAGS+="-undefined suppress -flat_namespace"
LDFLAGS+="-lcurl"

CFLAGS+=" $(eval echo \$CFLAGS_${LANG}_${OSNAME})"
LDFLAGS+=" $(eval echo \$LDFLAGS_${LANG}_${OSNAME})"

swig -I./src -${LANG} -c++ -o wrapper.cpp -outdir . ./http.i
g++ ${CFLAGS} ${SRC} wrapper.cpp ${LDFLAGS}
)
Notes:
  • ./script.sh python to generate python bindings.
  • Some of the code below has been modified for the example, the most important thing to understand is the way of use.
  • I work on Mac OS X, so you just have to add (CFLAGS|LDFLAGS)_<lang>_<os> for other configs.
  • It would be cleaner with a Makefile ;)
Cheers !
3 · 04

How to handle SSL certificates smartly in Firefox

SSL certificates validation is often annoying. In most of cases, the certificate is not acceptable by Firefox because it is self-signed by the server. Some of personal blogs does not have their certificate signed by a known authority.

I think Perspectives is a good solution for this problem, which does not concern only Firefox.

According to perspectives website:
Perspectives is a new approach to help clients securely identify Internet servers in order to avoid "man-in-the-middle" attacks. Perspectives is simple and cheap compared to existing approaches because it automatically builds a robust database of network identities using lightweight network probing by "network notaries" located in multiple vantage points across the Internet.

Firefox extension: http://www.cs.cmu.edu/~perspectives/firefox.html

18 · 01

FreeBSD on the ASUS Eee Box using an USB flash drive

I wanted my personal server to be closer to me. So I invested few days ago in the Asus Eee Box, thinking it is the best configuration for a light server at home.

I moved this blog and all my services from my dedicated server to my new one.

To setup FreeBSD on this kind of machine, you have two ways to do it:


Creating a bootable USB flash drive by using the original ISO image is a bit annoying if you haven't got a FreeBSD station yet. I have been using the fbsd2img.sh script,

I share my USB flash drive image: 7.1-RELEASE-i386-bootonly.img.
To setup the USB flash drive, use "dd" (/dev/XXX is the device of your USB flash drive):

dd if=7.1-RELEASE-i386-bootonly.img of=/dev/XXX bs=1m


Here is the result of the server hosting this blog :)

18 · 07

Subversion repository corruption: something to try when svnadmin recover does not work.

I had the wrong habit to keep my old projects in a subversion repository. It's not the good way of keeping code safe. svnadmin recover works when there is no corruption in your repository. If you have an old corrupted repository that you can't recover, you can first try a berkeley db recovery:
cd /var/svn/myrepos
dbX.X_recover
X.X is the berkelay db version of the repository. If svnadmin recover and db_recover don't work, try the solution below, it worked for me. You have to know the database version:
REPOS_PATH="/var/svn/myrepos"
DB_VERSION="4.3"
cd ${REPOS_PATH}/db
rm log.* __db.*
mv changes changes.old
mv copies copies.old
mv nodes nodes.old
mv representations representations.old
mv revisions revisions.old
mv strings strings.old
mv transactions transactions.old
mv uuids uuids.old
mv lock-tokens lock-tokens.old
mv locks locks.old
db${DB_VERSION}_dump changes.old | db${DB_VERSION}_load changes
db${DB_VERSION}_dump copies.old | db${DB_VERSION}_load copies
db${DB_VERSION}_dump nodes.old | db${DB_VERSION}_load nodes
db${DB_VERSION}_dump representations.old | db${DB_VERSION}_load representations
db${DB_VERSION}_dump revisions.old | db${DB_VERSION}_load revisions
db${DB_VERSION}_dump strings.old | db${DB_VERSION}_load strings
db${DB_VERSION}_dump transactions.old | db${DB_VERSION}_load transactions
db${DB_VERSION}_dump uuids.old | db${DB_VERSION}_load uuids
db${DB_VERSION}_dump lock-tokens.old | db${DB_VERSION}_load lock-tokens
db${DB_VERSION}_dump locks.old | db${DB_VERSION}_load locks
svnadmin recover ..
If binaries dbX.X_dump and dbX.X_load does not exist, you have to compile a old version of subversion with the berkeley database corresponding.
Thanks to dmp. Link: http://svn.haxx.se/users/archive-2005-07/0576.shtml
17 · 07

Gmail-Notify improvements and a modified behavior

Gmail-notify is a small program written in Python. I use it because it is light and it just do what I want. I am a regular user of the firefox extension gmail-notifyer and I was uncomfortable with the Gmail-notify behavior, so I wrote a little patch to make it more like I want. I also added the possibility to execute a command when a new message arrive. I use it to play a sound (aplay ~/sounds/mail.wav). I don't know your habits but maybe you could enjoy my modifications. Here is a small description:
  • A click on the event box close it.
  • A click on tray icon open the mailbox.
  • Mailbox is now open as HTTPS.
  • A command can be executed when a new mail is received (like playing a sound).
To use my modifications, download my patch, and apply it to gmail-notify-1.6.1.1:
wget http://garr.dl.sourceforge.net/sourceforge/gmail-notify/gmail-notify-1.6.1.1.tar.gz
wget http://zaphod.eu/pub/gmail-notify-1.6.1.1.patch tar zxvf gmail-notify-1.6.1.1.tar.gz
(cd gmail-notify ; patch -p1 < ../gmail-notify-1.6.1.1.patch)
rm gmail-notify-1.6.1.1.tar.gz
Then run gmail-notify.
gmail-notify/notifier.py
9 · 07

Ushare on Gentoo Linux

Ushare is a UPnP media server on linux. I use it to browse media files from my Xbox. There is no official gentoo ebuild. Sunrise Gentoo overlay provides an ebuild for Ushare, it requires some modifications to be used. I noticed some problems:
  1. Ushare daemon is configured to run as root. Without being paranoid, I don't want to entrust a root daemon which manipulate my precious media directory.
  2. Boot script in init.d directory is written for debian, so it does not work at all on Gentoo.
  3. Default configuration file contains some wrong variable names. So this configuration directives are ignored.
I rewrote the init.d script to work on Gentoo and to launch ushare daemon as nobody user. To sum up, Ushare can be deployed rapidly as follow: 1. Checkout Sunrise overlay with layman
emerge -v layman
layman -a sunrise
echo source /usr/portage/local/layman/make.conf >> /etc/make.conf
echo media-video/ushare >> /etc/portage/package.keywords
emerge -v ushare
2. Replace the Ushare boot script /etc/init.d/ushare by my script:
#!/sbin/runscript
#- by shad
DAEMON="/usr/bin/ushare"
NAME="ushare"
CONFIGFILE="/etc/ushare.conf"
OPTS="-f $CONFIGFILE"
PIDFILE="/var/run/ushare.pid"
USER="nobody"
[ -x $DAEMON ] || exit 0
start() {
ebegin "Starting $NAME"
start-stop-daemon --start --quiet --background --pidfile $PIDFILE \
--make-pidfile --exec /bin/su -- --command "$DAEMON $OPTS" $USER
eend $?
}
stop() {
ebegin "Stopping $NAME"
start-stop-daemon --stop --quiet --pidfile $PIDFILE
eend $?
}
3. The last thing to check is the name of configuration variables in /etc/ushare.conf. Make sure each variable starts with the "USHARE_" prefix.
Then,
/etc/init.d/ushare start
and watch your favorite movie on your Xbox 360 :)

Pages