1e8fc4975SFrançois Revol<?php 2e8fc4975SFrançois Revol 3e8fc4975SFrançois Revol/* 4e8fc4975SFrançois Revol * haiku.php - an online Haiku demo using qemu and vnc. 5e8fc4975SFrançois Revol * Copyright 2007, Francois Revol, revol@free.fr. 6e8fc4975SFrançois Revol */ 7e8fc4975SFrançois Revol 8e8fc4975SFrançois Revol// relative path to the vnc java applet jar 9e8fc4975SFrançois Revol// you must *copy* (apache doesn't seem to like symlinks) it there. 10e8fc4975SFrançois Revol 11e8fc4975SFrançois Revol// on debian, apt-get install vnc-java will put them in 12e8fc4975SFrançois Revol// /usr/share/vnc-java 13e8fc4975SFrançois Revol//define("VNCJAVA_PATH", "vnc-java"); 14e8fc4975SFrançois Revol//define("VNCJAR", "vncviewer.jar"); 15e8fc4975SFrançois Revol//define("VNCCLASS", "vncviewer.class"); 16e8fc4975SFrançois Revol 17e8fc4975SFrançois Revol// to use the tightvnc applet instead (supports > 8bpp): 18e8fc4975SFrançois Revol// on debian, apt-get install tightvnc-java will put them in 19e8fc4975SFrançois Revol// /usr/share/tightvnc-java 20e8fc4975SFrançois Revoldefine("VNCJAVA_PATH", "tightvnc-java"); 21e8fc4975SFrançois Revoldefine("VNCJAR", "VncViewer.jar"); 22e8fc4975SFrançois Revoldefine("VNCCLASS", "VncViewer.class"); 23e8fc4975SFrançois Revol 24e8fc4975SFrançois Revol// maximum count of qemu instances. 25e8fc4975SFrançois Revoldefine("MAX_QEMUS", 8); 26e8fc4975SFrançois Revol 27e8fc4975SFrançois Revol// size of the java applet, must match the default resolution of the image. 2852a7cf96SFrançois Revol//define("APPLET_WIDTH", "800"); 2952a7cf96SFrançois Revol//define("APPLET_HEIGHT", "600"); 3052a7cf96SFrançois Revoldefine("APPLET_WIDTH", "1024"); 3152a7cf96SFrançois Revoldefine("APPLET_HEIGHT", "768"); 32e8fc4975SFrançois Revol// vnc protocol base port. 33e8fc4975SFrançois Revoldefine("VNCPORTBASE", 5900); 34e8fc4975SFrançois Revol 35e8fc4975SFrançois Revol// timeout before the demo session is killed, as argument to /bin/sleep 36e8fc4975SFrançois Revoldefine("SESSION_TIMEOUT", "10m"); 37e8fc4975SFrançois Revol 38e8fc4975SFrançois Revol// path to qemu binary 39*c6f50a6aSFrançois Revoldefine("QEMU_BASE", "/usr/local"); 40*c6f50a6aSFrançois Revoldefine("QEMU_BIN", QEMU_BASE . "/bin/qemu"); 41*c6f50a6aSFrançois Revoldefine("QEMU_KEYMAPS", QEMU_BASE . "/share/qemu/keymaps"); 42e8fc4975SFrançois Revol// default arguments: no network, emulate tablet, readonly image file. 43*c6f50a6aSFrançois Revoldefine("QEMU_ARGS","-net none -usbdevice wacom-tablet -snapshot"); 44e8fc4975SFrançois Revol// absolute path to the image. 458ad2eabaSFrançois Revoldefine("QEMU_IMAGE_PATH","/home/revol/haiku/trunk/generated.x86/haiku.image"); 468ad2eabaSFrançois Revol// qemu 0.8.2 needs "", qemu 0.9.1 needs ":" 478ad2eabaSFrançois Revoldefine("QEMU_VNC_PREFIX", ":"); 48e8fc4975SFrançois Revol 49e8fc4975SFrançois Revol// name of session and pid files in /tmp 50e8fc4975SFrançois Revoldefine("QEMU_SESSFILE_TMPL", "qemu-haiku-session-"); 51e8fc4975SFrançois Revoldefine("QEMU_PIDFILE_TMPL", "qemu-haiku-pid-"); 52e8fc4975SFrançois Revol// name of session variable holding the qemu slot; not yet used correctly 53e8fc4975SFrançois Revoldefine("QEMU_IDX_VAR", "QEMU_HAIKU_SESSION_VAR"); 54e8fc4975SFrançois Revol 55e8fc4975SFrançois Revolsession_start(); 56e8fc4975SFrançois Revol 57e8fc4975SFrançois Revolif (isset($_GET['frame'])) { 58e8fc4975SFrançois Revol} 59e8fc4975SFrançois Revol 60e8fc4975SFrançois Revol?> 61e8fc4975SFrançois Revol<html> 62e8fc4975SFrançois Revol<head> 63cdbd6446SFrançois Revol<meta name="robots" content="noindex, nofollow, noarchive"> 64cdbd6446SFrançois Revol<title>Haiku Online Demo</title> 65e8fc4975SFrançois Revol</head> 66e8fc4975SFrançois Revol<script> 67e8fc4975SFrançois Revolfunction onPageUnload() { 68e8fc4975SFrançois Revol //window.open("<?php echo $_SERVER["SCRIPT_NAME"] . "?close"; ?>", "closing", "width=100,height=30,location=no,menubar=no,toolbar=no,scrollbars=no"); 69e8fc4975SFrançois Revol} 70e8fc4975SFrançois Revol</script> 71e8fc4975SFrançois Revol<?php 72e8fc4975SFrançois Revol 73*c6f50a6aSFrançois Revol$vnckeymap = "en-us"; 74e8fc4975SFrançois Revol 75e8fc4975SFrançois Revol// statics 76e8fc4975SFrançois Revol 77e8fc4975SFrançois Revol$count = $_SESSION['compteur']; 78e8fc4975SFrançois Revol//$count = $GLOBALS['compteur']; 79e8fc4975SFrançois Revol$closing = 0; 80e8fc4975SFrançois Revolif (isset($_GET['close'])) { 81e8fc4975SFrançois Revol $closing = 1; 82e8fc4975SFrançois Revol echo "<body>"; 83e8fc4975SFrançois Revol} else 84e8fc4975SFrançois Revol echo "<body onunload=\"onPageUnload();\">"; 85e8fc4975SFrançois Revol 86e8fc4975SFrançois Revolfunction dbg($str) 87e8fc4975SFrançois Revol{ 88e8fc4975SFrançois Revol echo "<div class=\"debug\">$str</div>\n"; 89e8fc4975SFrançois Revol} 90e8fc4975SFrançois Revol 91e8fc4975SFrançois Revolfunction err($str) 92e8fc4975SFrançois Revol{ 93e8fc4975SFrançois Revol echo "<div class=\"error\">$str</div>\n"; 94e8fc4975SFrançois Revol} 95e8fc4975SFrançois Revol 96e8fc4975SFrançois Revolfunction make_qemu_sessionfile_name($idx) 97e8fc4975SFrançois Revol{ 98e8fc4975SFrançois Revol return "/tmp/" . QEMU_SESSFILE_TMPL . $idx; 99e8fc4975SFrançois Revol} 100e8fc4975SFrançois Revol 101e8fc4975SFrançois Revolfunction make_qemu_pidfile_name($idx) 102e8fc4975SFrançois Revol{ 103e8fc4975SFrançois Revol return "/tmp/" . QEMU_PIDFILE_TMPL . $idx; 104e8fc4975SFrançois Revol} 105e8fc4975SFrançois Revol 106e8fc4975SFrançois Revolfunction find_qemu_slot() 107e8fc4975SFrançois Revol{ 108e8fc4975SFrançois Revol for ($idx = 0; $idx < MAX_QEMUS; $idx++) { 109e8fc4975SFrançois Revol $pidfile = make_qemu_pidfile_name($idx); 110e8fc4975SFrançois Revol $sessfile = make_qemu_sessionfile_name($idx); 111e8fc4975SFrançois Revol dbg("checking \"$pidfile\", \"$sessfile\"..."); 112e8fc4975SFrançois Revol if (!file_exists($pidfile) && !file_exists($sessfile)) { 113e8fc4975SFrançois Revol file_put_contents($sessfile, session_id()); 114e8fc4975SFrançois Revol $sid = file_get_contents($sessfile); 115e8fc4975SFrançois Revol if ($sid != session_id()) 116e8fc4975SFrançois Revol continue; 117e8fc4975SFrançois Revol $_SESSION[QEMU_IDX_VAR] = $idx; 118e8fc4975SFrançois Revol return $idx; 119e8fc4975SFrançois Revol } 120e8fc4975SFrançois Revol } 121e8fc4975SFrançois Revol return -1; 122e8fc4975SFrançois Revol} 123e8fc4975SFrançois Revol 124e8fc4975SFrançois Revolfunction qemu_slot() 125e8fc4975SFrançois Revol{ 126e8fc4975SFrançois Revol return $_SESSION[QEMU_IDX_VAR]; 127e8fc4975SFrançois Revol} 128e8fc4975SFrançois Revol 129e8fc4975SFrançois Revolfunction vnc_display() 130e8fc4975SFrançois Revol{ 131e8fc4975SFrançois Revol return qemu_slot(); 132e8fc4975SFrançois Revol} 133e8fc4975SFrançois Revol 134e8fc4975SFrançois Revolfunction vnc_port() 135e8fc4975SFrançois Revol{ 136e8fc4975SFrançois Revol return VNCPORTBASE + vnc_display(); 137e8fc4975SFrançois Revol} 138e8fc4975SFrançois Revol 139e8fc4975SFrançois Revolfunction is_my_session_valid() 140e8fc4975SFrançois Revol{ 141e8fc4975SFrançois Revol if (!isset($_SESSION[QEMU_IDX_VAR])) 142e8fc4975SFrançois Revol return 0; 143e8fc4975SFrançois Revol $idx = $_SESSION[QEMU_IDX_VAR]; 144e8fc4975SFrançois Revol $sessfile = make_qemu_sessionfile_name($idx); 145e8fc4975SFrançois Revol if (!file_exists($sessfile)) 146e8fc4975SFrançois Revol return 0; 147e8fc4975SFrançois Revol $qemusession=file_get_contents($sessfile); 148e8fc4975SFrançois Revol // has expired 149e8fc4975SFrançois Revol if ($qemusession != session_id()) { 150e8fc4975SFrançois Revol return 0; 151e8fc4975SFrançois Revol } 152e8fc4975SFrançois Revol return 1; 153e8fc4975SFrançois Revol} 154e8fc4975SFrançois Revol 155e8fc4975SFrançois Revol 156*c6f50a6aSFrançois Revol 157*c6f50a6aSFrançois Revol 158*c6f50a6aSFrançois Revolfunction probe_keymap() 159*c6f50a6aSFrançois Revol{ 160*c6f50a6aSFrançois Revol global $vnckeymap; 161*c6f50a6aSFrançois Revol // if the browser advertised a prefered lang... 162*c6f50a6aSFrançois Revol if (!isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) 163*c6f50a6aSFrançois Revol return; 164*c6f50a6aSFrançois Revol $langs = $_SERVER["HTTP_ACCEPT_LANGUAGE"]; 165*c6f50a6aSFrançois Revol $langs = ereg_replace(";q=[^,]*", "", $langs); 166*c6f50a6aSFrançois Revol $langs = str_replace(" ", "", $langs); 167*c6f50a6aSFrançois Revol $langs = split(",", $langs); 168*c6f50a6aSFrançois Revol //print_r($langs); 169*c6f50a6aSFrançois Revol $keymaps = scandir(QEMU_KEYMAPS); 170*c6f50a6aSFrançois Revol //print_r($keymaps); 171*c6f50a6aSFrançois Revol foreach($langs as $lang) 172*c6f50a6aSFrançois Revol { 173*c6f50a6aSFrançois Revol foreach($keymaps as $keymap) 174*c6f50a6aSFrançois Revol { 175*c6f50a6aSFrançois Revol if ($keymap == $lang) 176*c6f50a6aSFrançois Revol { 177*c6f50a6aSFrançois Revol dbg("Detected keymap '" . $keymap . "' from browser headers."); 178*c6f50a6aSFrançois Revol $vnckeymap = $keymap; 179*c6f50a6aSFrançois Revol return; 180*c6f50a6aSFrançois Revol } 181*c6f50a6aSFrançois Revol } 182*c6f50a6aSFrançois Revol } 183*c6f50a6aSFrançois Revol} 184*c6f50a6aSFrançois Revol 185*c6f50a6aSFrançois Revol 186e8fc4975SFrançois Revolfunction start_qemu() 187e8fc4975SFrançois Revol{ 188*c6f50a6aSFrançois Revol global $vnckeymap; 189e8fc4975SFrançois Revol $idx = find_qemu_slot(); 190e8fc4975SFrançois Revol if ($idx < 0) { 191e8fc4975SFrançois Revol err("No available qemu slot, please try later."); 192e8fc4975SFrançois Revol return $idx; 193e8fc4975SFrançois Revol } 194e8fc4975SFrançois Revol $pidfile = make_qemu_pidfile_name($idx); 195*c6f50a6aSFrançois Revol $cmd = QEMU_BIN . " " . QEMU_ARGS . " -k " . $vnckeymap . " -vnc " . QEMU_VNC_PREFIX . vnc_display() . " -pidfile " . $pidfile . " " . QEMU_IMAGE_PATH; 196e8fc4975SFrançois Revol 197e8fc4975SFrançois Revol if (file_exists($pidfile)) 198e8fc4975SFrançois Revol unlink($pidfile); 199e8fc4975SFrançois Revol dbg("Starting <tt>" . $cmd . "</tt>..."); 200e8fc4975SFrançois Revol 201e8fc4975SFrançois Revol $descriptorspec = array( 202e8fc4975SFrançois Revol // 0 => array("pipe", "r"), // stdin 203e8fc4975SFrançois Revol // 1 => array("pipe", "w"), // stdout 204e8fc4975SFrançois Revol // 2 => array("pipe", "w") // stderr 205e8fc4975SFrançois Revol ); 206e8fc4975SFrançois Revol //$cmd="/bin/ls"; 207e8fc4975SFrançois Revol //passthru($cmd, $ret); 208e8fc4975SFrançois Revol //dbg("ret=$ret"); 209e8fc4975SFrançois Revol $cmd .= " &"; 210e8fc4975SFrançois Revol $process = proc_open($cmd, $descriptorspec, $pipes); 211e8fc4975SFrançois Revol sleep(1); 212e8fc4975SFrançois Revol proc_close($process); 213e8fc4975SFrançois Revol 214e8fc4975SFrançois Revol dbg("Started QEMU."); 215e8fc4975SFrançois Revol $sessfile = make_qemu_sessionfile_name($idx); 216e8fc4975SFrançois Revol $cmd = "(sleep " . SESSION_TIMEOUT . "; kill -9 `cat " . $pidfile . "`; rm " . $pidfile . " " . $sessfile . ") &"; 217e8fc4975SFrançois Revol 218e8fc4975SFrançois Revol $process = proc_open($cmd, $descriptorspec, $wkpipes); 219e8fc4975SFrançois Revol sleep(1); 220e8fc4975SFrançois Revol proc_close($process); 221e8fc4975SFrançois Revol 222e8fc4975SFrançois Revol dbg("Started timed kill."); 223e8fc4975SFrançois Revol dbg("Ready for a " . SESSION_TIMEOUT . " session."); 224e8fc4975SFrançois Revol} 225e8fc4975SFrançois Revol 226e8fc4975SFrançois Revol 227e8fc4975SFrançois Revolfunction output_applet_code() 228e8fc4975SFrançois Revol{ 229e8fc4975SFrançois Revol $w = APPLET_WIDTH; 230e8fc4975SFrançois Revol $h = APPLET_HEIGHT; 231e8fc4975SFrançois Revol $port = vnc_port(); 232e8fc4975SFrançois Revol $vncjpath = VNCJAVA_PATH; 233e8fc4975SFrançois Revol $jar = VNCJAR; 234e8fc4975SFrançois Revol $class = VNCCLASS; 235e8fc4975SFrançois Revol echo "<applet code=$class codebase=\"$vncjpath/\" archive=\"$vncjpath/$jar\" width=$w height=$h> 236e8fc4975SFrançois Revol <param name=\"PORT\" value=\"$port\"> 237e8fc4975SFrançois Revol <!param name=\"HOST\" value=\"$HTTP_HOST\"><!-- no need --> 238e8fc4975SFrançois Revol <param name=\"PORT\" value=\"$port\"> 239e8fc4975SFrançois Revol <param name=\"PASSWORD\" value=\"\"> 240e8fc4975SFrançois Revol There should be a java applet here... make sure you have a JVM and it's enabled! 241e8fc4975SFrançois Revol </applet>"; 242e8fc4975SFrançois Revol} 243e8fc4975SFrançois Revol 244e8fc4975SFrançois Revoldbg("Checking if session is running..."); 245e8fc4975SFrançois Revol 246*c6f50a6aSFrançois Revol 247e8fc4975SFrançois Revolif (is_my_session_valid()) { 248e8fc4975SFrançois Revol dbg("Session running"); 249e8fc4975SFrançois Revol $qemuidx = qemu_slot(); 250e8fc4975SFrançois Revol} else if ($closing != 1) { 251e8fc4975SFrançois Revol dbg("Need to start qemu"); 252e8fc4975SFrançois Revol 253*c6f50a6aSFrançois Revol probe_keymap(); 254e8fc4975SFrançois Revol $qemuidx = start_qemu(); 255e8fc4975SFrançois Revol} 256e8fc4975SFrançois Revol 257e8fc4975SFrançois Revolif ($qemuidx >= 0) { 258e8fc4975SFrançois Revol if ($closing) { 259e8fc4975SFrançois Revol dbg("closing..."); 260e8fc4975SFrançois Revol unlink(make_qemu_sessionfile_name($qemuidx)); 261e8fc4975SFrançois Revol //unlink(make_qemu_sessionfile_name($qemuidx)); 262e8fc4975SFrançois Revol sleep(1); 263e8fc4975SFrançois Revol //echo "<script> self.close(\"closing\"); </script>"; 264e8fc4975SFrançois Revol } else { 265e8fc4975SFrançois Revol dbg("Waiting for vnc server..."); 266e8fc4975SFrançois Revol sleep(5); 267e8fc4975SFrançois Revol output_applet_code(); 268e8fc4975SFrançois Revol } 269e8fc4975SFrançois Revol} 270e8fc4975SFrançois Revol 271e8fc4975SFrançois Revol 272e8fc4975SFrançois Revol 273e8fc4975SFrançois Revol?> 274e8fc4975SFrançois Revol 275e8fc4975SFrançois Revol</body> 276e8fc4975SFrançois Revol</html> 277