Created
March 30, 2011 09:34
-
-
Save kanreisa/894125 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
/ >、 | |
厶/vvゝ | |
|| ・_・リ | |
川゚O O゚ | |
`` | |
*/ | |
/* | |
- 定数定義 - | |
*/ | |
define('IKA_ADDR', '192.168.12.33'); | |
define('IKA_PORT', 10080); | |
define('IKA_BACKLOG', 32); | |
define('IKA_ERR_LV', E_ALL); // 全てのエラーを出力 | |
define('IKA_NAME', 'Test'); | |
/* | |
- 変数定義 - | |
*/ | |
$master = NULL; | |
$sockets = array(); | |
$clients = array(); | |
/* | |
- 特殊定数 - | |
*/ | |
if(defined('__DIR__')==false){ | |
define('__DIR__', dirname(__FILE__)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
- func.system - | |
*/ | |
function make_log($type,$message,$debug=false) | |
{ | |
$error = NULL; | |
if($debug==true) $error = ' #'.__LINE__.':'.socket_strerror(socket_last_error()); | |
return '['.date('H:i:s').']['.$type.'] '.$message.$error.PHP_EOL; | |
} | |
function make_id($ip,$port) | |
{ | |
return $ip.':'.$port; | |
} | |
/* | |
- func.websocket - | |
*/ | |
function realize_header($buffer) | |
{ | |
$resource = $code = null; | |
preg_match('/GET (.*?) HTTP/', $buffer, $match) && $resource = $match[1]; | |
preg_match("/\r\n(.*?)\$/", $buffer, $match) && $code = $match[1]; | |
$headers = array(); | |
foreach(explode("\r\n", $buffer) as $line) | |
{ | |
if (strpos($line, ': ') !== false) | |
{ | |
list($key, $value) = explode(': ', $line); | |
$headers[trim($key)] = trim($value); | |
} | |
} | |
return array($resource, $headers, $code); | |
} | |
function make_security_key($key1, $key2, $code) | |
{ | |
return md5( | |
pack('N', cook_security_key($key1)). | |
pack('N', cook_security_key($key2)). | |
$code, | |
true | |
); | |
} | |
function cook_security_key($key) | |
{ | |
preg_match_all('/[0-9]/', $key, $number); | |
preg_match_all('/ /', $key, $space); | |
if ($number && $space) { | |
return @implode('', $number[0]) / count($space[0]); | |
} | |
return ''; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/php -q | |
<?php | |
/* | |
/ >、 | |
厶/vvゝ WebSocket Server Daemon | |
|| ・_・リ - Ikasumi - ver.1 By: kanreisa | |
川゚O O゚ | |
`` | |
Usage: | |
(launch) | |
php ikasumi.php | |
php ikasumi.php >> /dev/null & | |
php ikasumi.php >> ../log/ikasumi/ikasumi.log & | |
(access) | |
ws://host:port/resource | |
*/ | |
require 'def.inc.php'; /* 変数定数定義 */ | |
require 'func.inc.php'; /* 関数定義 */ | |
/* | |
- PHP実行環境設定 - | |
*/ | |
error_reporting(IKA_ERR_LV); // エラー表示設定 | |
set_time_limit(0); // タイムアウト無効 | |
ob_implicit_flush(1); // php_cli用設定 | |
/* | |
- 起動メッセージ - | |
*/ | |
echo ' / >、', PHP_EOL, | |
"厶/\033[36mvv\033[0mゝ WebSocket Server Daemon for {".IKA_NAME.'}', PHP_EOL, | |
"\033[36m||\033[0m ・_・\033[36mリ\033[0m \033[46m Ikasumi \033[0m ver.1 By: kanreisa", PHP_EOL, | |
"\033[36m川\033[0m゚O O゚", PHP_EOL; | |
/* | |
- Socket通信初期化 - | |
*/ | |
require 'init_sock.inc.php'; | |
/* | |
- メインルーチン - | |
*/ | |
echo make_log('system','Ikasumi server is started. PORT='. IKA_PORT); | |
echo make_log('system','Ikasumi directory is '. __DIR__); | |
/* run loop */ | |
while(true): | |
$changed = $sockets; | |
socket_select($changed, $write=NULL, $except=NULL, NULL); | |
foreach($changed as $socket) | |
{ | |
if($socket==$master) | |
gosub('accept connection');//新規接続 | |
else | |
{ | |
gosub('init client_id'); | |
if(($bytes=socket_recv($socket, $buffer, 2048, 0))==0)//なにか受信 | |
gosub('close connection');//なんもなかったら切る | |
else | |
{ | |
/* do handshake or other */ | |
if(isset($clients[$client_id]['handshake'])==false) | |
{ | |
list($resource, $headers, $securityCode) = realize_header($buffer);//ヘッダ解析 | |
if(trim($buffer)=='<policy-file-request/>') | |
{ | |
gosub('response policy for flash');//Flash互換対応 | |
gosub('close connection');//done | |
} | |
else if(isset($headers['Origin'])==false) | |
{ | |
echo make_log('info', '<denied> '. $client_id); | |
gosub('close connection');//WSプロトコルでないので切る | |
} | |
else | |
gosub('response handshake');//接続要求に応答 | |
} | |
else | |
{ | |
// do | |
$buffer = str_replace('・・', '', $buffer); | |
echo make_log('test', '<read> '.$client_id.' >'. $buffer); | |
} | |
} | |
} | |
} | |
usleep(5000); // 0.005s | |
endwhile; | |
/* | |
- sub.routine - | |
*/ | |
function gosub($do) | |
{ | |
global $master, $sockets, $clients, $socket, $resource, $headers, $securityCode; | |
global $client_id, $client_ip, $client_port; | |
/* switch */ | |
switch($do): | |
case 'accept connection': | |
/* try accept connection */ | |
if(($accepted=socket_accept($master))===false) | |
{ | |
// failed | |
echo make_log('warn', 'socket_accept() failed', true); | |
return; | |
} | |
socket_getpeername($accepted, $client_ip, $client_port); | |
$client_id = make_id($client_ip,$client_port); | |
/* decide */ | |
if(isset($clients[$client_id]['accepted'])==true) | |
{ | |
// rejected | |
socket_close($accepted); | |
echo make_log('info', '<rejected> '.$client_id, true); | |
} | |
else | |
{ | |
// accept | |
echo make_log('info', '<accepted> '.$client_id, true); | |
// add | |
$clients[$client_id]['accepted'] = true; | |
$clients[$client_id]['socket'] = $accepted; | |
$sockets[] = $accepted; | |
} | |
return; | |
case 'init client_id': | |
/* init client_id from ip,port */ | |
socket_getpeername($socket, $client_ip, $client_port); | |
$client_id = make_id($client_ip,$client_port); | |
return; | |
case 'response policy for flash': | |
/* responce cross-domain-policy */ | |
$hdr = '<?xml version="1.0"?>'. | |
'<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">'. | |
'<cross-domain-policy>'. | |
' <allow-access-from domain="*" to-ports="'.IKA_PORT.'"/>'. | |
'</cross-domain-policy>'; | |
socket_write($socket, $hdr.chr(0), strlen($hdr.chr(0))); | |
echo make_log('info', '<response> '.$client_id.' [GET]policy-file',true); | |
return; | |
case 'response handshake': | |
/* process for handshake */ | |
if (isset($headers['Sec-WebSocket-Key1']) && isset($headers['Sec-WebSocket-Key2'])) | |
{ | |
$securityResponse = make_security_key($headers['Sec-WebSocket-Key1'], $headers['Sec-WebSocket-Key2'], $securityCode); | |
$hdr = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" . | |
"Upgrade: WebSocket\r\n" . | |
"Connection: Upgrade\r\n" . | |
"Sec-WebSocket-Origin: " . $headers['Origin'] . "\r\n" . | |
"Sec-WebSocket-Location: ws://" . $headers['Host'] . $resource . "\r\n" . | |
"\r\n".$securityResponse; | |
} | |
else | |
{ | |
$hdr = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" . | |
"Upgrade: WebSocket\r\n" . | |
"Connection: Upgrade\r\n" . | |
"WebSocket-Origin: " . $headers['Origin'] . "\r\n" . | |
"WebSocket-Location: ws://" . $headers['Host'] . $resource . "\r\n" . | |
"\r\n"; | |
} | |
socket_write($socket, $hdr.chr(0), strlen($hdr.chr(0))); | |
echo make_log('info', '<response> '.$client_id.' [GET]'.$resource, true); | |
$clients[$client_id]['handshake'] = true; // save handshake status | |
return; | |
case 'close connection': | |
/* close connection */ | |
unset($clients[$client_id]); | |
if(($index=array_search($socket, $sockets))>=0) array_splice($sockets, $index, 1); | |
socket_close($socket); | |
echo make_log('info', '<closed> '.$client_id, true); | |
return; | |
endswitch; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
- Socket通信初期化 - | |
*/ | |
$master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die(make_log('error','socket_create():', true)); | |
socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1) or die(make_log('error','socket_option():', true)); | |
socket_bind($master, IKA_ADDR, IKA_PORT) or die(make_log('error','socket_bind():', true)); | |
socket_listen($master, IKA_BACKLOG) or die(make_log('error','socket_listen():', true)); | |
$sockets[] = $master; // add |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment