#!/usr/bin/perl package User; sub new{ my $this = shift; my ($id, $pass, $host, $win, $lose, $draw, $down, $last_access, $sock ) = ("","","",0,0,0,0,0,0); my $obj = { id => $id, pass => $pass, host => $host, win => $win, lose => $lose, draw => $draw, down => $down, last_access => $last_access, sock => $sock }; bless $obj, $this; return $obj; } package SockBuf; sub new{ my $this = shift; my ($sock, $buf, $host ); my $obj = { sock => $sock, buf => $buf , host => $host }; bless $obj, $this; return $obj; } package main; $SIG{INT} = \&sig_exit_int; $SIG{HUP} = \&sig_exit_hup; $SIG{QUIT} = \&sig_exit_quit; $SIG{TERM} = \&sig_exit_term; $SIG{PIPE} = \&sig_exit_pipe; sub sig_exit_int { print "INT\n";sig_exit();} sub sig_exit_hup { print "HUP\n";sig_exit();} sub sig_exit_quit { print "QUIT\n";sig_exit();} sub sig_exit_term { print "TERM\n";sig_exit();} sub sig_exit_pipe { print "PIPE\n";sig_exit();} sub sig_exit { print "exit user $UserCount"; $/ = ""; $\ = ""; open( OUT, ">users.tmp" ) or die; for ( $i = 0 ; $i < $UserCount ; $i++ ){ print ( OUT "ID:$Users[$i]->{id}\n" ); print ( OUT "PASS:$Users[$i]->{pass}\n" ); print ( OUT "HOST:$Users[$i]->{host}\n" ); print ( OUT "WIN:$Users[$i]->{win}\n" ); print ( OUT "LOSE:$Users[$i]->{lose}\n" ); print ( OUT "DRAW:$Users[$i]->{draw}\n" ); print ( OUT "DOWN:$Users[$i]->{down}\n" ); print ( OUT ".\n" ); } close( OUT ); print "thank you\n"; exit; } sub read_users{ $exist = 0; open( IN, "users" ) or return; while( ){ if( $_ eq ".\n" ){ $exist = 0; next; } if ( $exist == 0 ){ next;} ( $key, $value ) = split( /:/ , $_ , 2 ); $value =~ s/\n$//g; if ( $key eq "ID" && $value ne "" ){ $Users[$UserCount] = new User(); $Users[$UserCount]->{id} = $value; $UserCount++; $exist = 1; }elsif( $key eq "PASS" ){ $Users[$UserCount - 1]->{pass} = $value; }elsif( $key eq "HOST" ){ $Users[$UserCount - 1]->{host} = $value; }elsif( $key eq "WIN" ){ $Users[$UserCount - 1]->{win} = $value - 0; }elsif( $key eq "LOSE" ){ $Users[$UserCount -1]->{lose} = $value - 0; }elsif( $key eq "DRAW" ){ $Users[$UserCount -1]->{draw} = $value - 0; }elsif( $key eq "DOWN" ){ $Users[$UserCount -1]->{down} = $value - 0; } } close( IN ); print "Load user $UserCount\n"; } use IO::Socket::INET; use IO::Select; $MAX_LOGIN=100; $MAX_BATTLE=5; @Users;#登録ユーザー $UserCount = 0; @Logins;#ログインしているユーザー $LoginCount = 0; @Socks;#接続しているソケット管理用 $SockCount = 0; @Ports = (xxxx,xxxx,xxxx,xxxx,xxxx);#対戦鯖のポート情報 @DownTimes = (0,0,0,0,0);#対戦鯖が落ちた時間 #対戦情報を初期化 for( $i = 0 ; $i < 10 ; $i++ ){ $Battles[$i] = ""; $BattleUsers[$i] = -1; } read_users(); # use URI::Escape; # you'll need this later i guess ... $Main = new IO::Socket::INET (LocalHost => 'www.xxxxx.net', LocalPort => xxxx, Listen => 5, Proto => 'tcp', Reuse => 1 ) || die $!; $zero = chr(0); $/ = $zero; $\ = $zero; $| = 1; # Initialise IO::Select ------------------------------------------------ $Handles = new IO::Select(); $Handles->add($Main); LISTEN: while (1) { ($pending) = IO::Select->select($Handles, undef, undef, 60); foreach $sock (@$pending) { if ($sock == $Main) { #新規接続 my $newsock = $sock->accept(); if ( $SockCount >= $MAX_LOGIN ){ print $newsock qq||; $newsock->close(); next; } $newsock->autoflush(); $sockaddr = 'S n N x8'; $hersockaddr = $newsock->peername(); ($family, $port, $heraddr) = unpack($sockaddr,$hersockaddr); $ip = int( $heraddr / (256*256*256) ) . "." . ( int( $heraddr / (256*256) ) % 256 ) . "." . ( int( $heraddr / (256) ) % 256 ) . "." . ( $heraddr % 256 ); $host = ""; $host = gethostbyaddr(pack("C4", split(/\./, $ip)), 2); if( $host eq "" ){ $host = $ip; } $Handles->add($newsock); $Socks[$SockCount] = new SockBuf; $Socks[$SockCount]->{sock} = $newsock; $Socks[$SockCount]->{buf} = ""; $Socks[$SockCount]->{host} = $host; $SockCount++; print "connect SockCount:$SockCount;\n"; next; } print ("1\n"); my $buf = <$sock>; print ("2\n"); $login_index = -1; $sock_index = -1; foreach ( $i = 0 ; $i < $SockCount ; $i++ ){ if ( $Socks[$i]->{sock} == $sock ){ $sock_index = $i; last; } } foreach ( $i = 0 ; $i < $LoginCount ; $i++ ){ if ( $Users[$Logins[$i]]->{sock} == $sock ){ $login_index = $i; last; } } if (!$buf) { #切断 $Handles->remove($sock); if( $sock_index > -1 ){ for( $i = $sock_index ; $i < $SockCount - 1; $i++ ){ $Socks[$i] = $Socks[$i + 1]; } } $sock->close(); $SockCount--; print "down SockCount:$SockCount;\n"; if( $login_index > -1 ){ $tmp_id = $Users[$Logins[$login_index]]->{id}; #バトル中に落ちたのじゃないかチェック for( $i = 0 ; $i < 10 ; $i++ ){ if( $Battles[$i] eq $tmp_id ){ $Battles[$i] = ""; change_battle_status( int( $i / 2 ) ); } } # for( $i = $login_index ; $i < $LoginCount - 1; $i++ ){ $Logins[$i] = $Logins[$i + 1]; } $LoginCount--; print "down LoginCount:$LoginCount;\n"; for( $i = 0 ; $i < $LoginCount ; $i++ ){ $tmp_sock = $Users[$Logins[$i]]->{sock}; print $tmp_sock qq||; } } next; } #メッセージ受信 chomp $buf; if( $sock_index < 0 ){next;} #最後まで受信したか判定 $Socks[$sock_index]->{buf} .= $buf; $last = '/>$'; if( $Socks[$sock_index]->{buf} !~ /$last/ ){next;} #ステータスとIDの抽出 $buf = $Socks[$sock_index]->{buf}; $Socks[$sock_index]->{buf} = ""; ($status) = $buf =~ / s="(.*?)"/; ($id) = $buf =~ / id="(.*?)"/; if( $status eq "login" ){ if( $login_index > -1 ){next;} $pass = ""; ($pass) = $buf =~ / pass="(.*?)"/; #登録ユーザー? $exist = 0; for( $i = 0 ; $i < $UserCount ;$i++ ){ if( $Users[$i]->{id} eq $id ){ $exist = 1; $user_index = $i; last; } } if( $exist ){ #登録ユーザーの場合 if( !check_pass( $pass, $Users[$user_index]->{pass} ) ){ print $sock qq||; next; } $exist = 0; for( $i = 0 ; $i < $LoginCount ;$i++ ){ if( $Logins[$i] == $user_index ){ #2重ログインは許さない $exist = 1; print $sock qq||; last; } } if( $exist ){ next; } $Users[$user_index]->{sock} = $sock; $Users[$user_index]->{host} = $Socks[$sock_index]->{host}; $Logins[$LoginCount] = $user_index; $LoginCount++; print "login LoginCount:$LoginCount\n"; }else{ #未登録ユーザー if( !check_id_char($id) ){ print $sock qq||; next; } $Users[$UserCount] = new User; $Users[$UserCount]->{id} = $id; $Users[$UserCount]->{pass} = make_pass( $pass ); $Users[$UserCount]->{sock} = $sock; $Users[$UserCount]->{host} = $Socks[$sock_index]->{host}; $Logins[$LoginCount] = $UserCount; $user_index = $UserCount; $UserCount++; $LoginCount++; print "login LoginCount:$LoginCount\n"; print "login UserCount:$UserCount\n"; #デバッグ用ログ(どれくらいの人がくるのかのログ)) $\ = ""; open( IDS, ">> ids" ); print ( IDS "$id:$Socks[$sock_index]->{host}\n" ); close( IDS ); $\ = $zero; } #ログイン通知 for( $i = 0 ; $i < $LoginCount ; $i++ ){ $tmp_sock = $Users[$Logins[$i]]->{sock}; if( $Logins[$i] == $user_index ){ $send = qq||; for( $j = 0 ; $j < $LoginCount ; $j++ ){ if( $Logins[$j] == $user_index ){next;} $send .= qq||; } for( $j = 0 ; $j < $MAX_BATTLE ; $j++ ){ $p1 = $Battles[$j * 2]; $p2 = $Battles[$j * 2 + 1]; if( $DownTimes[$j] > 0 ){ $send .= qq||; }else{ $send .= qq||; } } $send .= ""; print $tmp_sock $send; }else{ print $tmp_sock qq||; } } next; }elsif( $status eq "chat" && $login_index > -1){ #チャット $id = ""; ($id) = $buf =~ / id="(.*?)"/; $msg = ""; ($msg) = $buf =~ / msg="(.*?)"/; #ログインユーザー? $exist = 0; for( $i = 0 ; $i < $LoginCount ;$i++ ){ if( $Users[$Logins[$i]]->{id} eq $id ){ $exist = 1; $user_index = $Logins[$i]; last; } } $fail = " "; if( $exist ){ $tmp_sock = $Users[$user_index]->{sock}; print $tmp_sock qq||; }else{ print $sock qq||; $fail = "f"; } next; }elsif( $status eq "battle_enter" && $login_index > -1){ #バトル入場 $index = ""; ($index) = $buf =~ / index="(.*?)"/; $index -= 0; $Battles[$index * 2] = $Users[$Logins[$login_index]]->{id}; $Battles[$index * 2 + 1] = ""; $BattleUsers[$index * 2] = search_user_index( $Users[$Logins[$login_index]]->{id} ); $BattleUsers[$index * 2 + 1] = -1; $DownTimes[$index] = 0; change_battle_status( $index ); }elsif( $status eq "battle_start" && $login_index > -1){ #バトルスタート $index = ""; ($index) = $buf =~ / index="(.*?)"/; $index -= 0; if( $Battles[$index * 2] eq "" ){ $Battles[$index * 2] = $Users[$Logins[$login_index]]->{id}; $BattleUsers[$index * 2] = search_user_index( $Users[$Logins[$login_index]]->{id} ); }else{ $Battles[$index * 2 + 1] = $Users[$Logins[$login_index]]->{id}; $BattleUsers[$index * 2 + 1] = search_user_index( $Users[$Logins[$login_index]]->{id} ); } change_battle_status( $index ); next; }elsif( $status eq "battle_drop" && $login_index > -1){ #バトル落ち $index = ""; ($index) = $buf =~ / index="(.*?)"/; $index -= 0; if( $DropTimes[$index] > 0 ){ next; } if( $Battles[$index * 2] eq $Users[$Logins[$login_index]]->{id} ){ $Battles[$index * 2] = ""; change_battle_status( $index ); }elsif( $Battles[$index * 2 + 1] eq $Users[$Logins[$login_index]]->{id} ){ $Battles[$index * 2 + 1] = ""; change_battle_status( $index ); } next; }elsif( $status eq "battle_end" && $login_index > -1 ){ #勝敗決定 $index = ""; ($index) = $buf =~ / index="(.*?)"/; $index -= 0; $result = ""; ($result) = $buf =~ / result="(.*?)"/; if( $Battles[$index * 2] eq $Users[$Logins[$login_index]]->{id} ){ $user_index1 = $Logins[$login_index]; $user_index2 = $BattleUsers[$index * 2 + 1]; }else{ $user_index1 = $Logins[$login_index]; $user_index2 = $BattleUsers[$index * 2]; } if ( $result eq "win" ){ $Users[$user_index1]->{win}++ if ( $user_index1 > -1 ); $Users[$user_index2]->{lose}++ if ( $user_index2 > -1 ); }elsif( $result eq "lose" ){ $Users[$user_index1]->{lose}++ if ( $user_index1 > -1 ); $Users[$user_index2]->{win}++ if ( $user_index2 > -1 ); }elsif( $result eq "draw" ){ $Users[$user_index1]->{draw}++ if ( $user_index1 > -1 ); $Users[$user_index2]->{draw}++ if ( $user_index2 > -1 ); }elsif( $result eq "down" ){ $Users[$user_index2]->{down}++ if ( $user_index2 > -1 ); } $send = qq||; if( $user_index1 > -1 ){ $send .= qq||; } if( $user_index2 > -1 ){ $send .= qq||; } $send .= ""; for( $i = 0 ; $i < $LoginCount ; $i++ ){ $tmp_sock = $Users[$Logins[$i]]->{sock}; print $tmp_sock $send; } $Battles[$index * 2] = ""; $Battles[$index * 2 + 1] = ""; $BattleUsers[$index * 2] = -1; $BattleUsers[$index * 2 + 1] = -1; change_battle_status( $index ); next; }elsif( $status eq "battle_down" && $login_index > -1 ){ #鯖がおちた $index = ""; ($index) = $buf =~ / index="(.*?)"/; $index -= 0; if( $DownTimes[$index] > 0 ){next;} $Battles[$index * 2] = ""; $Battles[$index * 2 + 1] = ""; $BattleUsers[$index * 2] = -1; $BattleUsers[$index * 2 + 1] = -1; $DownTimes[$index] = time(); change_battle_status( $index ); next; } } } sub change_battle_status{ my ( $index ) = @_; my ( $p1, $p2 ) = ( $Battles[$index * 2], $Battles[$index * 2+1]); for( $i = 0 ; $i < $LoginCount ; $i++ ){ $tmp_sock = $Users[$Logins[$i]]->{sock}; if( $DownTimes[$index] > 0 ){ print $tmp_sock qq||; }else{ print $tmp_sock qq||; } } } sub search_user_index{ my ( $id ) = @_; for( $i = 0 ; $i < $UserCount ; $i++ ){ if( $Users[$i]->{id} eq $id ){ return $i } } return -1; } sub make_pass{ my ( $pass ) = @_; my $times = time; my $salt = substr($times,-2,2); return crypt( $pass, $salt ); } sub check_pass{ my ( $newpass, $pass ) = @_; if( $pass eq crypt( $newpass, substr( $pass, 0, 2 ) ) ){ return 1; }else{ return 0; } } sub check_id_char{ my ( $id ) = @_; if ( $id =~ m|[^A-Za-z0-9\-_.]| ){ return 0; }else{ return 1; } }