<?php namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\Log; use App\Classes\Protocol\{Binkp,DNS,EMSI}; use App\Classes\Sock\Exception\SocketException; use App\Classes\Sock\SocketServer; use App\Models\Setup; class ServerStart extends Command { private const LOGKEY = 'CSS'; /** * The name and signature of the console command. * * @var string */ protected $signature = 'server:start'; /** * The console command description. * * @var string */ protected $description = 'Start Server'; /** * Execute the console command. * * @return int * @throws SocketException */ public function handle(): int { Log::info(sprintf('%s:+ Server Starting (%d)',self::LOGKEY,getmypid())); $o = Setup::findOrFail(config('app.id')); $start = collect(); if ($o->binkp_active) $start->put('binkp',[ 'address'=>$o->binkp_bind, 'port'=>$o->binkp_port, 'proto'=>SOCK_STREAM, 'class'=>new Binkp($o), ]); if ($o->emsi_active) $start->put('emsi',[ 'address'=>$o->emsi_bind, 'port'=>$o->emsi_port, 'proto'=>SOCK_STREAM, 'class'=>new EMSI($o), ]); if ($o->dns_active) $start->put('dns',[ 'address'=>$o->dns_bind, 'port'=>$o->dns_port, 'proto'=>SOCK_DGRAM, 'class'=>new DNS(), ]); $children = collect(); Log::debug(sprintf('%s:# Servers [%d]',self::LOGKEY,$start->count())); if (! $start->count()) { Log::alert(sprintf('%s:! No servers configured to start',self::LOGKEY)); return self::FAILURE; } pcntl_signal(SIGCHLD,SIG_IGN); foreach ($start as $item => $config) { Log::debug(sprintf('%s:- Starting [%s] (%d)',self::LOGKEY,$item,getmypid())); $pid = pcntl_fork(); if ($pid === -1) die('could not fork'); // We are the child if (! $pid) { Log::withContext(['pid'=>getmypid()]); Log::info(sprintf('%s:= Started [%s]',self::LOGKEY,$item)); $server = new SocketServer($config['port'],$config['address'],$config['proto']); $server->handler = [$config['class'],'onConnect']; try { $server->listen(); } catch (SocketException $e) { if ($e->getMessage() === 'Can\'t accept connections: "Success"') Log::debug(sprintf('%s:! Server Terminated [%s]',self::LOGKEY,$item)); else Log::emergency(sprintf('%s:! Uncaught Message: %s',self::LOGKEY,$e->getMessage())); } Log::info(sprintf('%s:= Finished: [%s]',self::LOGKEY,$item)); // Child finished we need to get out of this loop. return self::SUCCESS; } Log::debug(sprintf('%s:- Forked for [%s] (%d)',self::LOGKEY,$item,$pid)); $children->put($pid,$item); } // Wait for children to exit while ($x=$children->count()) { // Wait for children to finish $exited = pcntl_wait($status); if ($exited < 0) abort(500,'Something strange for status: '.serialize($status)); Log::info(sprintf('%s:= Exited: #%d [%s]',self::LOGKEY,$x,$children->pull($exited))); } // Done Log::debug(sprintf('%s:= Finished.',self::LOGKEY)); return self::SUCCESS; } }