ClientUser = $User; $this->Listener = socket_create (AF_INET, SOCK_STREAM, SOL_TCP); socket_getsockname ($Socket, $IP); socket_bind ($this->Listener, $IP); socket_listen ($this->Listener); // Remember this context self::restoreListener (); } public function handle ($Socket) { // Process an incoming connection if ($Socket == $this->Listener) { // Assign sockets $this->Local = socket_accept ($this->Listener); $this->Remote = socket_create (AF_INET, SOCK_STREAM, SOL_TCP); // Connect remote side $p = strpos ($this->RemoteAddr, ":"); socket_connect ($this->Remote, substr ($this->RemoteAddr, 0, $p), intval (substr ($this->RemoteAddr, $p + 1))); $this->Authenticated = false; setContextSocket ($this->Local, $this); setContextSocket ($this->Remote, $this); // Stop waiting for events here unsetSocketContext ($this->Listener); socket_getpeername ($this->Local, $this->ClientIP, $this->ClientPort); print "Accepting connection on BOS-Forwarder from " . $this->ClientIP . ":" . $this->ClientPort . "\n"; return; } elseif ($Socket == $this->Remote) { if (!($Flap = flapRead ($this->Remote, true, "BOS<<"))) return $this->close ("Read FLAP from remote"); self::log ($Flap, false); writeFlap ($this->Local, $Flap, false, "BOS>>"); return; } // Read Flap from local connection if (!($Flap = flapRead ($this->Local, true, "BOS>>"))) return $this->close ("Read FLAP from client"); // Try to authenticate client if (!$this->Authenticated) { // Check initial version on FLAP if (substr ($Flap ["Payload"], 0, 4) != chr (0) . chr (0) . chr (0) . chr (1)) return $this->close ("Invalid protocol"); // Create a copy of the Flap $xFlap = $Flap; // Remove version from Flap $xFlap ["Payload"] = substr ($xFlap ["Payload"], 4); $xFlap ["Length"] -= 4; // Read TLVs from CLI_COOKIE $TLV = flapTreatTLV ($xFlap); // Search for a cookie $haveCookie = false; foreach ($TLV as $Item) if (($Item ["Type"] == 0x0006) && ($haveCookie = ($Item ["Payload"] == $this->RemoteCookie))) break; if (!$haveCookie) return $this->close ("Cookie missing"); print "BOS-Connection authenticated\n"; // Initiate remote connection $this->Authenticated = true; // Remove the listening socket socket_shutdown ($this->Listener, 2); socket_close ($this->Listener); } self::log ($Flap, true); // Forward FLAP to remote side writeFlap ($this->Remote, $Flap, false, "BOS<<"); } private function restoreListener () { // Set context for listener socket setContextSocket ($this->Listener, $this); } public function setAddress ($Address) { $this->RemoteAddr = $Address; } public function setCookie ($Cookie) { $this->RemoteCookie = $Cookie; } public function getAddress () { socket_getsockname ($this->Listener, $IP, $Port); return $IP . ":" . $Port; } private function log ($Flap, $fromClient) { // Make sure that log is open if (!is_resource ($this->logFD)) { if (!is_resource ($this->logFD = @fopen ("logs/" . $this->ClientUser . "_" . time () . ".xml", "w"))) return; // Start logging fwrite ($this->logFD, "\n"); } // Log header of Flap fwrite ($this->logFD, " \n"); // Log payload of Flap if ($Flap ["Length"] > 0) { // Log payload of Flap fwrite ($this->logFD, " \n" . htmlentities (dumpData ($Flap ["Payload"], " ", true)) . " \n"); // Handle SNACs on Channel 0x02 if ($Flap ["Channel"] == 0x02) { $SNAC = flapReadSNAC ($Flap); fwrite ($this->logFD, " \n" . " \n" . htmlentities (dumpData ($SNAC ["Payload"], " ", true)) . " \n"); // Handle TLVs on SNAC global $TLV_SNACs; if (isset ($TLV_SNACs [$SNAC ["Family"]]) && in_array ($SNAC ["Subtype"], $TLV_SNACs [$SNAC ["Family"]])) { $Items = flapTreatTLV ($SNAC); foreach ($Items as $Item) fwrite ($this->logFD, " \n" . htmlentities (dumpData ($Item ["Payload"], " ", true)) . " \n"); } fwrite ($this->logFD, " \n"); } } // Close the Flap on log fwrite ($this->logFD, " \n"); } private function closeLog () { // Check if the log is already closed if (!is_resource ($this->logFD)) return; // Close the log fwrite ($this->logFD, "\n"); fclose ($this->logFD); $this->logFD = null; } protected function close ($Reason = "") { if (is_resource ($this->Local)) { print "Client on BOS discarded\n"; if ($Reason != "") print "Reason: " . $Reason . "\n"; unsetSocketContext ($this->Local); unsetSocketContext ($this->Remote); socket_shutdown ($this->Local, 2); socket_close ($this->Local); socket_shutdown ($this->Remote, 2); socket_close ($this->Remote); } self::closeLog (); if (!$this->Authenticated) return $this->restoreListener (); } } ?>