Windows7でコマンドプロンプトからの接続で、HTTPプロキシ設定が反映されない\(^o^)/

プロキシ環境下のネットワークで、コマンドプロンプトからのHTTP/HTTPS接続がうまくいかない時があります。これはIEのオプションで設定したプロキシ設定は、そのままではコマンドプロンプトに反映されないため、です。

こんなとき、Windows XPであれば、コマンドプロンプトから

proxycfg -u

とすれば、おkだったのですが、Windows7になってproxycfg.exe自体が廃止されてたーーーー\(^o^)/オワタ



で、調べてみると、netshという新しいコマンドが追加されていました。

Windows7の場合、以下のコマンドでIEオプションのプロキシ設定を反映できます。

netsh winhttp import proxy source=ie

設定されたかどうかを確認するには、

netsh winhttp show proxy
現在の WinHTTP プロキシ設定:
プロキシサーバー: proxy.example.com
バイパス一覧: ....

のようにして確認できます。

他にも、netshにはいろいろな機能があり、netsh ?でヘルプが表示されます。
Windows7では、とにかくネットワーク周りで困ったときはnetsh、とおぼえておきましょう。

C:\windows\system32>netsh ?

使用法: netsh [-a エイリアス ファイル名] [-c コンテキスト] [-r リモート コンピュ
ーター名] [-u [ドメイン名\]ユーザー名] [-p パスワード | *]
[コマンド | -f スクリプト ファイル名]

使用できるコマンドは次のとおりです:

このコンテキストのコマンド:
? - コマンドの一覧を表示します。
add - エントリの一覧に構成エントリを追加します。
advfirewall - 'netsh advfirewall' コンテキストに変更します。
bridge - 'netsh bridge' コンテキストに変更します。
delete - エントリの一覧から構成エントリを削除します。
dhcpclient - 'netsh dhcpclient' コンテキストに変更します。
dnsclient - 'netsh dnsclient' コンテキストに変更します。
dump - 構成スクリプトを表示します。
exec - スクリプト ファイルを実行します。
firewall - 'netsh firewall' コンテキストに変更します。
help - コマンドの一覧を表示します。
http - 'netsh http' コンテキストに変更します。
interface - 'netsh interface' コンテキストに変更します。
ipsec - 'netsh ipsec' コンテキストに変更します。
lan - 'netsh lan' コンテキストに変更します。
mbn - 'netsh mbn' コンテキストに変更します。
namespace - 'netsh namespace' コンテキストに変更します。
nap - 'netsh nap' コンテキストに変更します。
netio - 'netsh netio' コンテキストに変更します。
p2p - 'netsh p2p' コンテキストに変更します。
ras - 'netsh ras' コンテキストに変更します。
rpc - 'netsh rpc' コンテキストに変更します。
set - 構成の設定を更新します。
show - 情報を表示します。
trace - 'netsh trace' コンテキストに変更します。
wcn - 'netsh wcn' コンテキストに変更します。
wfp - 'netsh wfp' コンテキストに変更します。
winhttp - 'netsh winhttp' コンテキストに変更します。
winsock - 'netsh winsock' コンテキストに変更します。
wlan - 'netsh wlan' コンテキストに変更します。

MacのTerminalでプロキシを設定する

MacのTerminalは、コンパネの「ネットワーク環境設定」のプロキシ設定を拾ってくれないようです(´・ω・`)ショボーン


というわけでTerminalにproxyを設定する。

Terminalを開いて、

$ export http_proxy="http://servername:port"
$ export https_proxy="https://servername:port"

とすればよい。

解除するときは、

$ export http_proxy=""
$ export https_proxy=""

まあそれだけなんですがあんまりネットに載ってないようなので困っている初心者のために....

ブラウザを常にシークレットモードで起動する

ブラウザのプライバシーが気になる方へオススメの設定。

1. Chromeの代わりにSRWare Ironを入れる。(Chromeのままでも別に構いませんがGoogleは裏でいろいろ情報を送信するので…)

2. スタートボタンのメニューのIronのショートカットを右クリックしてプロパティを開き、リンク先を「"C:\Program Files\SRWare Iron\iron.exe" --incognito」に書き換える。(--incognitoがポイント)

これでブラウザが常時シークレットモードで起動します。

ついでに、

3. プロパティのショートカットキーにCtrl+F7とかを登録する。

と、Ctrl+F7でブラウザがシークレットモードで起動するのでオススメです。

バッファローのLinkStationが\(^o^)/オワタので救済する

LinkStation(機種名: LS-WTGL/R1)をRAID1で運用していたのですが、
ネットワークから見えなくなり/(^o^)\オワタ


…のですが、以下の方法でとりあえず救済できたのでメモ。


LinkStation(最近のモデルはどうか知りませんが機種名LSで始まるわりと古いタイプ)は、HDDのディスクフォーマットにxfsという古いunixファイルシステムの一つを採用しており、そのままだとHDDを取り外してPCに繋いでも認識されません。

以下、救済したときの手順。

  1. LinkStationを分解し、HDDを取り出す。ネジ3本で簡単に外れます。
  2. USB-SATA変換ケーブルを利用してPCに接続。PCはDVDから起動できるものであれば何でも良いです。今回はたまたま持ってたのでこれを使用しました。(HDDをUSB SATA&IDE-USB2.0変換アダプタケーブル Groovy社のUD-500SA)
  3. こういうケーブルが手元にない場合、SATAのHDDとDVDドライブを搭載しているデスクトップPCが1台あればHDDを換装して代用できます。(OSの起動はDVDから行うのでOSのHDDは取り外しても大丈夫)
  4. knoppix Linuxの起動DVDを作成。http://www.rcis.aist.go.jp/project/knoppix/ からKNOPPIX6.7.1 DVD日本語版(LCAT対応) 3.7GB (knoppix_v6.7.1DVD_20110914-20111018.iso)というのをダウンロードしてきてISOファイルをそのままDVD-Rに焼く。
  5. DVDをPCに挿入し、USB-SATAケーブルでつないだHDDの電源を入れ、PCを再起動。
  6. DVDからknoppixが起動したら、以下のようにコマンドを入力します。

$ su (rootになる。パスワード不要)
# ls -la /dev/sd* (シリアルデバイスの一覧を出力する)
/dev/sda
/dev/sda1
: (中略)
/dev/sdb
/dev/sdb1
/dev/sdb2
/dev/sdb3
/dev/sdb4
/dev/sdb5
/dev/sdb6

この部分は利用するPCによって違うはずですが、私の場合は「sdb」に認識されました。

1〜6まであるのがLinkStationから取り出したHDDです。(/dev/sdb しか見えないときは、HDDの電源が入っていることを確認後、PCを再起動すると出てくるかもしれません)

1から6をそれぞれマウントしてみると中身がわかりますが、必要なのはとりあえず/dev/sdb6だけです。これをマウントします。

# mkdir /home/linkstation (homeに作成しておくと後でsambaするときに楽なので)
# mount -t xfs /dev/sdb6 /home/linkstation

これでエラーが出なければOK。/home/linkstation/ の下にファイルが見えるはずです。

運悪くエラーが出たときは、以下を試す。

# xfs_check /dev/sdb6

ERROR: The filesystem has valuable metadata changes in a log which needs to be replayed. Mount the filesystem to replay the log, and unmount it before re-running xfs_check. If you are unable to mount the filesystem, then use the xfs_repair -L option to destroy the log and attempt a repair. Note that destroying the log may cause corruption -- please attempt a mount of the filesystem before doing this.

と表示されたら、-Lオプションを試します。

# xfs_repair -L /dev/sdb6

このあと、再度、mount -t xfs /dev/sdb6 /home/linkstation してエラーが出なければOK。

このままLANで共有してしまいましょう。

# useradd linkstation
# smbpasswd -a linkstation
(任意のパスワードを入力)
# /etc/init.d/samba start

これでknoppixがそのまま共有フォルダとしてLAN上の他のPCから見えるようになりました。

LAN上の他のPCから、フォルダを開き、「アドレス」欄に\\192.168.xxx.xxx (IPアドレスはifconfigコマンドで確認できる)と入力してアクセスすると、パスワードを聞いてきますので、userはlinkstation、パスワードは上記で入力したパスワードを入力すると/home/linkstationの中身を共有することができます。見えているうちに他の正常なドライブにデータを救済しましょう。

おわり。

VC++の__int64の罠にハマった\(^o^)/

VC++で4GB(unsigned 32bit境界)を超えるファイルサイズを扱うアプリケーションを作っていて
VC++コンパイラの癖の罠にハマった\(^o^)/のでメモ。

問題:次のようなコードはどういう結果になりますか?(・ω・`)

#include "stdafx.h"


void _testfunc(unsigned __int64 num)
{
	printf("%I64d (%I64x)\r\n", num, num);
}

int _tmain(int argc, _TCHAR* argv[])
{
	unsigned int a = 0xffffffff;
	unsigned int b = 0x10000000;
	unsigned __int64 c = a + b;
	unsigned __int64 d = (unsigned __int64)a + (unsigned __int64)b;

	_testfunc( a + b);
	_testfunc( c );
	_testfunc( d );
	
	return 0;
}


これを実行するとこうなる。


つまり正しい結果が出るのは_testfunc( d );の

	unsigned __int64 d = (unsigned __int64)a + (unsigned __int64)b;

という処理をしたときのみ。


よく考えれば当たり前なんですが、

	unsigned int a = 0xffffffff;
	unsigned int b = 0x10000000;
	unsigned __int64 c = a + b;

という計算は間違いで、a+bという計算はたとえ代入先が__int64 cと定義されていても一時的にint(32bit)として加算され32bitを超えるビットが落ちてしまうのでござる。



これはまあ分かるにしても、今回ハマったのは、

void _testfunc(unsigned __int64 num);

と定義してある、つまり引数に64bit値をとる関数プロトタイプ宣言をしてあっても、うっかり

	_testfunc( a + b);

と書いてしまったらうまくいかないんだな(´・ω・`)



つまり

	_testfunc( (__int64)a + (__int64)b);

として渡してやらないと正しい値が渡らない。



ねーよwwwwww


と思う方は例えばこんなコードを想定。

	_testfunc( blocksize * num_blocks );

この場合、blocksizeもnum_blocksも__int64で宣言されていれば問題ないのですが、構造上blocksizeは最大32KBだからunsigned long blocksize; でいいや、と思っていると罠にハマる。




これはコンパイル結果のアセンブラを調べてみればわかる。

void _testfunc(unsigned __int64 num)
{
004113B0  push        ebp  
004113B1  mov         ebp,esp 
004113B3  sub         esp,0C0h 
004113B9  push        ebx  
004113BA  push        esi  
004113BB  push        edi  
004113BC  lea         edi,[ebp-0C0h] 
004113C2  mov         ecx,30h 
004113C7  mov         eax,0CCCCCCCCh 
004113CC  rep stos    dword ptr es:[edi] 

	printf("%I64d (%I64x)\r\n", num, num);
(途中省略)
00411408  ret              



int _tmain(int argc, _TCHAR* argv[])
{
00411420  push        ebp  
00411421  mov         ebp,esp 
00411423  sub         esp,0F8h 
00411429  push        ebx  
0041142A  push        esi  
0041142B  push        edi  
0041142C  lea         edi,[ebp-0F8h] 
00411432  mov         ecx,3Eh 
00411437  mov         eax,0CCCCCCCCh 
0041143C  rep stos    dword ptr es:[edi] 

	unsigned int a = 0xffffffff;
0041143E  mov         dword ptr [a],0FFFFFFFFh 

	unsigned int b = 0x10000000;
00411445  mov         dword ptr [b],10000000h 

	unsigned __int64 c = a + b;
0041144C  mov         eax,dword ptr [a] 
0041144F  add         eax,dword ptr [b]        # eax,ecxは32bit汎用レジスタ
00411452  xor         ecx,ecx                   # 上位32ビットをクリア
00411454  mov         dword ptr [c],eax 
00411457  mov         dword ptr [ebp-20h],ecx 

	unsigned __int64 d = (unsigned __int64)a + (unsigned __int64)b;
0041145A  mov         eax,dword ptr [a] 
0041145D  xor         ecx,ecx 
0041145F  mov         edx,dword ptr [b] 
00411462  xor         esi,esi 
00411464  add         eax,edx 
00411466  adc         ecx,esi                   # 上位32ビットキャリーをちゃんと足している
00411468  mov         dword ptr [d],eax 
0041146B  mov         dword ptr [ebp-30h],ecx 

	_testfunc( a + b);
0041146E  mov         eax,dword ptr [a] 
00411471  add         eax,dword ptr [b] 
00411474  xor         ecx,ecx                   # 上位32ビットをクリア
00411476  push        ecx  
00411477  push        eax  
00411478  call        _testfunc (4111D6h) 
0041147D  add         esp,8 

	_testfunc( c );
00411480  mov         eax,dword ptr [ebp-20h] 
00411483  push        eax  
00411484  mov         ecx,dword ptr [c] 
00411487  push        ecx  
00411488  call        _testfunc (4111D6h) 
0041148D  add         esp,8 

	_testfunc( d );
00411490  mov         eax,dword ptr [ebp-30h] 
00411493  push        eax  
00411494  mov         ecx,dword ptr [d] 
00411497  push        ecx  
00411498  call        _testfunc (4111D6h) 
0041149D  add         esp,8 
	
	return 0;
(以下略)

CentOS5.5のPHPを最新版にアップグレードする

CentOSが他のディストリビューションに比べて一番ダメダメなところは、RPMのレポジトリに登録されている各種ライブラリのバージョンがとにかく古いことなんだな(´・ω・`)


PHPが5.1.6と古いのでバージョンアップすることにした。
ググルとぁゃしぃutterなんちゃらとかremiなんちゃらとかのレポジトリをrpm importして使え!といっているサイトもありますがぁゃしぃものは信じない主義なので自分でソースからインスコする。


PHPをソースからインスコするときは、libxml2, apache-apxs2, libmysqlclientに依存するのでこれらを先に入れる。


libxml2の開発パッケージをインストール。

# cd /usr/local/src/ (自分でいれたソースコードはここに集める主義)
# yum install libxml2
# yum install libxml2-devel

確認。

# whereis libxml2
libxml2: /usr/local/lib/libxml2.a /usr/local/lib/libxml2.la /usr/local/lib/libxml2.so

apxs2を先にインストールしておく。これはhttp-develパッケージに入っている。

# yum install httpd-devel
# whereis apxs
apxs: /usr/sbin/apxs /usr/share/man/man8/apxs.8.gz
(パスを通しておく)
# export PATH=$PATH:/usr/sbin/

libmysqlclientはmysql-develパッケージに入ってる。

# yum install mysql-devel


事前にRPM版のPHP5.1.6を削除。

# yum erase php\*

PHPのソース最新版をphp.netからダウンロードしてきてインストール。

# tar xvjf php-5.3.6.tar.bz2
# cd php-5.3.6/
# make clean (念のため)
# export LDFLAGS="-L/usr/lib64/mysql" (64bit版の場合)
# ./configure --prefix=/usr --with-apxs2=/usr/sbin/apxs --enable-mbstring --enable-mbregex --with-mysql --with-mysql-sock=/var/lib/mysql/mysql.sock --with-pdo-mysql --enable-zend-multibyte --with-zlib-dir=/usr/lib --with-config-file-path=/etc/

    • with-config-file-pathを指定しないときのデフォルトパスは /usr/local/lib/php.ini となるので注意。CentOSのデフォルトでは/etc/php.iniになっているので合わせる。
    • apxs2のパスはwhereis apxsとするとわかる。
    • prefixのパスはまつびに/を付けない。with-config-fileのパスは最後に/を付ける点に注意。

pearとかは特に--disable-pearとかしない限り自動的に入るので大丈夫。

# make
# make install

php.iniをコピー。

# cp php.ini-production /etc/php.ini
# ln -s /etc/php.ini /usr/local/lib/php.ini

ソースからインストールしたphp.iniは以下の3箇所を修正する必要があるので注意。

  1. display_errors = Off に変更 (デフォルトでOnになっている)
  2. short_open_tag = On に変更 (あまり推奨されてないけど、<?=$var?>形式が使えないといくつかのオープンソースは正しく動作しないので。)
  3. date.timezone = Asia/Tokyo を追加。(ないとWarningが出まくる)

あとはお好みで。

インストール結果は次のようにして確認&保存しておくと後で便利。

# php --info > phpinfo.txt

Apache再起動。

# /sbin/service httpd restart

Flash/Flexでsocketを利用するときのセキュリティサンドボックス侵害について

Flashで動くIRCクライアントを作っていたらハマった/(^o^)\のでメモ。



FlashActionScript3でsocketを利用しているとき、FlashDevelopなどのローカル開発環境では動くのに、サーバにswfをアップロードしたら動かない\(^o^)/オワタ


...というときは、セキュリティサンドボックス侵害エラーになっていることがあります。
(他に相対パスが間違ってるとかアフォなミスもよくやりがちなので注意)



まず、これが原因であることを確認するには、Flashplayerのデバッグ版というのを使うと良い。
これはAdobeのサイト

http://www.adobe.com/support/flashplayer/downloads.html

でダウンロード出来る。上記のページでWindows版のところにリストアップされている「Download the Windows Flash Player 10.3 Projector content debugger (EXE, 6.50MB)」というのをダウンロードするとスタンドアロン版のFlashPlayerデバッグ版がダウンロードされるので、これをダブルクリックして実行し、Fileメニューからswfへのパス(htmlへのパスではないよ)を入力するとサーバ上にアップロードされたswfファイルを直接実行出来る。


これで実行してみて30秒から60秒たって「セキュリティサンドボックス侵害によりサーバ****.comのport NNNNからデータを受信できません」的な(´・ω・)??

SecurityError: [SecurityErrorEvent type="securityError" bubbles=false cancelable=false eventPhase=2 text="Error #2048: セキュリティサンドボックス侵害 : http://www.myserver.jp/myflashmovie.swf は www.myserver.jp:6667 からデータを読み込めません。"]


問題の原因の詳細は、
Flash Player 9および10におけるポリシーファイル関連の変更点
http://www.adobe.com/jp/devnet/flashplayer/articles/fplayer9_security_04.html
の「ソケットポリシーファイル」(socket policy file) を参照のこと。


さてこのページを読んでも日本語が下手クソすぎて何を言っているのかわからん。Adobeよ、もうちょっとマシな翻訳家を雇え(#゚Д゚)ゴルァ!!



で試行錯誤の結果、以下の方法で回避できたよー、という報告をいたしますでござる。


まず上記のページを読むと、とにかくソケットポリシーファイルというのを、ActionScriptからconnectしにいく相手のサーバが供給しないといけないことがわかる。これは例えば以下のようなファイルである。これは http://www.adobe.com/devnet/flashplayer/articles/socket_policy_files.html においてあったサンプル。

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
<!-- Policy file for xmlsocket://socks.example.com -->
<cross-domain-policy>
   <!-- This is a master-policy file -->
   <site-control permitted-cross-domain-policies="master-only"/>
   <!-- Instead of setting to-ports="*",
administrators can use ranges and commas -->
   <!-- This will allow access to ports 123, 456, 457, and 458 -->
   <allow-access-from domain="swf.example.com" to-ports="123,456-458" />
</cross-domain-policy>

(swf.sample.comのところは、自分のFlashを置くwebサーバのドメインに)


このファイルを、Flashがconnectしにいく相手のサーバの適当なところに置く。たとえば、

# mkdir /usr/local/flashpolicyd
# vi /usr/local/flashpolicyd/socket_policy_file.xsd

として保存する。拡張子は.xsdで。


さて、このファイル自体は極めて簡単なのですが、問題はこのファイルをTCP/IPポート843でListenしてフィードしてやらねばならんのだ。ここである程度自分でいじれるサーバ(root権限あり)でないと自動的に\(^o^)/オワタになる。

http://www.adobe.com/devnet/flashplayer/articles/socket_policy_files.html

で、このページのby Peleus Uhleyとかのドヤ顔写真をさておいてよく読むと「ソケットポリシーファイルサーバ」なるプログラムのサンプルソースコードが公開されている。上記のページの右上の「Sample files [http://www.adobe.com/content/dotcom/en/devnet/flashplayer/articles/socket_policy_files/_jcr_content/articlePrerequistes/multiplefiles/node_1277808777771/file.res/flashpolicyd_v0.6[1].zip:title=flashpolicyd_v0.6.zip]」
だよ、わかった?


これをダウンロードして解凍するとPerl版とPython版の2種類のflashpolicyd(フラッシュポリシーデーモン)というファイルが入っている。

  • flashpolicyd.pl (Perl版)
  • flashpolicyd.py (Python版)

いまどきPerlPythonも入ってるでしょ。ということでどちらでもいいんですが、私の環境ではPython版はそのままでは動かんかったよー/(^o^)\

ちなみにPython版を動かしたときに出るエラーは次のとおりで、これはPythonのバージョンが古いためにwith file(path) as f: 形式の書式に対応していないのが原因。よく読んだらソースコード中にPythonのバージョンは2.5以上が必要と書いてありました。

環境によってはPythonのアップグレードが難しい場合もあると思われるので、Python2.4でも動作するように修正したバージョンを下記に貼っておきます。

それから今どきのLinuxサーバはiptablesが動いているでしょうからポート開放も忘れずに。

# vi /etc/sysconfig/iptables

のファイルに

  • A INPUT -p tcp -m tcp --dport 843 -j ACCEPT

と追加したあと、

# /sbin/service iptables restart (reloadはなかった)

とすればおk。
iptablesのコマンドで直接ルールを追加する方法もありますが、チェインの中のフィルタリング順序がわけわからなくなりがちなので上記のように直接/etc/sysconfig/iptablesをいじってからreloadするほうが個人的に趣味なんだからいいだろうるせーよ)


さてこれで準備ができた。ポリシーファイルサーバを実行してみよう。

# cd /usr/local/flashpolicyd
# ./flashpolicyd.py --file=socket_policy_file.xsd
Listening on port 843

おお、聞いてる聞いてる。

さっき動かなかったFlashをもう一度起動してみるとログがコンソールに表示される。

Connection from 192.168.8.4:1462
Valid request received
Sent policy file

みたいに表示されればおk。
動いたー\(^o^)/



あとはこれだとコマンドを終了したら繋がらなくなってしまうので、常にバックグラウンドで動かしておいてやる。

/etc/rc.d/rc.local に以下の1行を追加。

/usr/local/flashpolicyd/flashpolicyd.py --file=/usr/local/flashpolicyd/socket_policy_file.xsd 2>&1 > /dev/null &

以上。

  • -

以下はPython版をPython2.4でも動くように修正したバージョンです。ご参考まで。

#!/usr/bin/env python
#
# flashpolicyd.py
# Simple socket policy file server for Flash
#
# Usage: flashpolicyd.py [--port=N] --file=FILE
#
# Logs to stderr
# Requires Python 2.4 or later

#from __future__ import with_statement

import sys
import optparse
import socket
import thread
import exceptions
# import contextlib

VERSION = 0.1

class policy_server(object):
    def __init__(self, port, path):
        self.port = port
        self.path = path
        self.policy = self.read_policy(path)
        self.log('Listening on port %d\n' % port)
        try:
            self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
        except AttributeError:
            # AttributeError catches Python built without IPv6
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        except socket.error:
            # socket.error catches OS with IPv6 disabled
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(('', port))
        self.sock.listen(5)
    def read_policy(self, path):
        f = open(path, 'rb')
        policy = f.read(10001)
        if len(policy) > 10000:
            raise exceptions.RuntimeError('File probably too large to be a policy file',
                                              path)
        if 'cross-domain-policy' not in policy:
            raise exceptions.RuntimeError('Not a valid policy file',
                                              path)
        f.close();
        return policy
    def run(self):
        try:
            while True:
                thread.start_new_thread(self.handle, self.sock.accept())
        except socket.error, e:
            self.log('Error accepting connection: %s' % (e[1],))
    def handle(self, conn, addr):
        addrstr = '%s:%s' % (addr[0],addr[1])
        try:
            self.log('Connection from %s' % (addrstr,))
            # with contextlib.closing(conn):
            try:
                # It's possible that we won't get the entire request in
                # a single recv, but very unlikely.
                request = conn.recv(1024).strip()
                if request != '<policy-file-request/>\0':
                    self.log('Unrecognized request from %s: %s' % (addrstr, request))
                    return
                self.log('Valid request received from %s' % (addrstr,))
                conn.sendall(self.policy)
                self.log('Sent policy file to %s' % (addrstr,))
            finally:
                conn.close();
        except socket.error, e:
            self.log('Error handling connection from %s: %s' % (addrstr, e[1]))
        except Exception, e:
            self.log('Error handling connection from %s: %s' % (addrstr, e[1]))
    def log(self, str):
        print >>sys.stderr, str

def main():
    parser = optparse.OptionParser(usage = '%prog [--port=PORT] --file=FILE',
                                   version='%prog ' + str(VERSION))
    parser.add_option('-p', '--port', dest='port', type=int, default=843,
                      help='listen on port PORT', metavar='PORT')
    parser.add_option('-f', '--file', dest='path',
                      help='server policy file FILE', metavar='FILE')
    opts, args = parser.parse_args()
    if args:
        parser.error('No arguments are needed. See help.')
    if not opts.path:
        parser.error('File must be specified. See help.')

    try:
        policy_server(opts.port, opts.path).run()
    except Exception, e:
        print >> sys.stderr, e
        sys.exit(1)
    except KeyboardInterrupt:
        pass

if __name__ == '__main__':
    main()