servermgrv2/public/hpilo/js/VMconnection.js
2023-07-17 21:09:49 +09:00

390 lines
17 KiB
JavaScript

function init() {
window.File && window.FileReader && window.FileList && window.Blob || $.log("The File APIs are not fully supported in this browser.");
}
function VMconnection(vm_conn, id) {
function onOpen(evt) {
sendClientHello();
}
function onClose(evt) {
-1 !== tmrId && (clearInterval(tmrId), tmrId = -1);
}
function onError(evt) {
$.log(evt.data);
}
function sendClientHello() {
client_hello[0] = 16, client_hello[1] = devType, setupSessionKey(), that.doSend(client_hello);
}
function setupSessionKey() {
for (var sessionKey = document.cookie.replace(/(?:(?:^|.*;\s*)sessionKey\s*\=\s*([^;]*).*$)|^.*$/, "$1"), i = 0; i < sessionKey.length; i++) client_hello[2 + i] = sessionKey.charCodeAt(i);
}
function keepalive(ka) {
const KEEPALIVE = 2;
ka ? flags |= KEEPALIVE : flags &= -3;
}
function disconnect(dc) {
const DISCONNECT = 4;
dc ? flags |= DISCONNECT : flags &= -5;
}
this.file, this.media_sz, this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT, this.event_state = 0,
this.media, this.wsUri = iLO.getBaseUrl("", "wss:") + "wss/vmport";
var websocket, flags, devType = vm_conn, vmConnId = id, client_hello = new Uint8Array(34), tmrId = -1, that = this;
this.getDevType = function() {
return devType;
}, this.getVmConnId = function() {
return vmConnId;
}, this.getWebsocket = function() {
return websocket;
}, this.getTmrId = function() {
return tmrId;
}, this.setTmrId = function(id) {
tmrId = id;
}, this.setMedia_sz = function(size) {
this.media_sz = size;
}, this.setFile = function(f) {
this.file = f;
}, this.createWebSocket = function() {
if (websocket && iLO.isFunction(websocket.close)) try {
websocket.onclose = function() {}, websocket.close();
} catch (e) {}
try {
websocket = new WebSocket(this.wsUri), websocket.binaryType = "arraybuffer", websocket.onopen = function(evt) {
onOpen(evt);
}, websocket.onmessage = function(evt) {
that.onMessage(evt);
}, websocket.onerror = function(evt) {
onError(evt);
}, websocket.onclose = function(evt) {
onClose(evt);
};
} catch (e) {
var dlgMsg = iLO.translateString("IRC.error.newWebsocketEx") + "<br />Error: " + e.Message, msgBox = {
titleKey: "IRC.error.newWebsocketExTitle",
icon: myIcons.critical,
message: dlgMsg
};
return void iLO.alert(msgBox);
}
}, this.client_test_unit_ready = function() {
this.fdd_state === fddStateEnum.MEDIA_NOT_PRESENT ? that.sendRespHeader(2, 58, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_CHANGED ? (that.sendRespHeader(6, 40, 0, 0),
this.fdd_state = 2) : that.sendRespHeader(0, 0, 0, 0);
}, this.sendKeepAlive = function() {
keepalive(!0), that.sendRespHeader(0, 0, 0, 0), keepalive(!1);
}, this.closeVMconnection = function() {
websocket && 1 === websocket.readyState && (showIrcToast({
text: iLO.translateString("vm.processVMEject"),
type: "ok",
position: "bottom-right"
}), disconnect(!0), that.sendRespHeader(0, 0, 0, 0), disconnect(!1));
}, this.sendRespHeader = function(sense_key, asc, ascq, length) {
var magic = 195936478, resp_hdr = new Uint8Array(16);
resp_hdr[0] = 255 & magic, resp_hdr[1] = magic >> 8 & 255, resp_hdr[2] = magic >> 16 & 255,
resp_hdr[3] = magic >> 24 & 255, resp_hdr[4] = 255 & flags, resp_hdr[5] = flags >> 8 & 255,
resp_hdr[6] = flags >> 16 & 255, resp_hdr[7] = flags >> 24 & 255, resp_hdr[8] = this.media,
resp_hdr[9] = sense_key, resp_hdr[10] = asc, resp_hdr[11] = ascq, resp_hdr[12] = 255 & length,
resp_hdr[13] = length >> 8 & 255, resp_hdr[14] = length >> 16 & 255, resp_hdr[15] = length >> 24 & 255,
that.doSend(resp_hdr);
}, this.doSend = function(message) {
websocket && websocket.send(message);
};
}
function VMconnection_fd(vm_conn, id) {
VMconnection.call(this, vm_conn, id), this.buffer = new Uint8Array(131072), this.lba,
this.writeLen;
}
function ejectDevice(obj) {
var id = $(obj).data("id");
vm_conn[id].closeVMconnection();
}
function imgFileHandler(fileInput) {
var dlgMsg = "", id = $(fileInput).data("id");
if (/(\.img)$/i.exec(fileInput.value)) vm_conn[id] = new VMconnection_fd(vmConnType.FLOPPY, id),
vm_conn[id].setFile(fileInput.files[0]), vm_conn[id].setMedia_sz(fileInput.files[0].size),
vm_conn[id].createWebSocket(); else if (/(\.iso)$/i.exec(fileInput.value)) vm_conn[id] = new VMconnection(vmConnType.CDROM, id),
vm_conn[id].setFile(fileInput.files[0]), vm_conn[id].setMedia_sz(fileInput.files[0].size),
vm_conn[id].createWebSocket(); else {
dlgMsg = iLO.translateString("IRC.error.UnsupportedFileType");
var msgBox = {
titleKey: "IRC.title.Denied",
icon: myIcons.critical,
message: dlgMsg,
closeOnClick: !1
};
iLO.alert(msgBox);
}
}
const SCSI_READ_CAPACITY = 37, SCSI_READ_CAPACITIES = 35, SCSI_SEND_DIAGNOSTIC = 29, SCSI_START_STOP_UNIT = 27, SCSI_TEST_UNIT_READY = 0, SCSI_PA_MEDIA_REMOVAL = 30, SCSI_READ_10 = 40, SCSI_READ_12 = 168, SCSI_WRITE_10 = 42, SCSI_WRITE_12 = 170, CDROM_SECTOR_SIZE = 2048, FLOPPY_SECTOR_SIZE = 512, CDROM_MAX_CHUNK_SIZE = 32768, FLOPPY_MAX_CHUNK_SIZE = 32768;
var fddStateEnum = {
MEDIA_NOT_PRESENT: 0,
MEDIA_CHANGED: 1,
MEDIA_READY: 2
}, vmConnType = {
FLOPPY: 1,
CDROM: 2,
USB: 3
}, maxNumVMConn = 10, vm_conn = new Array(maxNumVMConn);
window.onbeforeunload = function() {
for (var i = 0; maxNumVMConn > i; i++) if ("undefined" != typeof vm_conn[i] && vm_conn[i].getWebsocket() && iLO.isFunction(vm_conn[i].getWebsocket().close)) try {
vm_conn[i].getWebsocket().onclose = function() {}, vm_conn[i].getWebsocket().close();
} catch (e) {}
}, window.addEventListener("load", init, !1), VMconnection.prototype.onMessage = function(evt) {
var currTmrId = this.getTmrId();
if (-1 !== currTmrId && (clearInterval(currTmrId), this.setTmrId(-1)), evt.data instanceof Blob) ; else if (evt.data instanceof ArrayBuffer) {
var byteArray = new Uint8Array(evt.data);
if (4 === evt.data.byteLength) {
var status = byteArray[0], zero = byteArray[1], dlgMsg = "";
if (32 == status && 0 == zero) VMconnection.numDevs++, showIrcToast({
text: iLO.translateString("vm.imgInserted"),
type: "ok",
position: "bottom-right"
}); else {
switch (status) {
case 33:
dlgMsg = iLO.translateString("IRC.error.DriveInUse");
break;
case 34:
dlgMsg = iLO.translateString("IRC.error.InvalidKey");
break;
case 35:
dlgMsg = iLO.translateString("IRC.error.MediaNotLicensed");
break;
case 36:
dlgMsg = iLO.translateString("IRC.error.KeyExpired");
break;
case 37:
dlgMsg = iLO.translateString("IRC.error.DriveNotConfigured");
break;
case 38:
dlgMsg = iLO.translateString("IRC.error.MediaPermitRequired");
break;
default:
dlgMsg = iLO.translateString("IRC.error.CannotConnectDrive");
}
if (dlgMsg.length > 0) {
var msgBox = {
titleKey: "IRC.title.UnableToConnect",
icon: myIcons.critical,
message: dlgMsg,
closeOnClick: !1
};
iLO.alert(msgBox);
}
}
} else 12 === evt.data.byteLength && this.processSCSIRequest(byteArray);
}
currTmrId = setInterval(this.sendKeepAlive, 2e3), this.setTmrId(currTmrId);
}, VMconnection.prototype.processSCSIRequest = function(byteArray) {
switch (renderer && renderer.onvmactivity && renderer.onvmactivity(), 0 === this.media_sz ? (this.media = 0,
this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT, this.event_state = 0) : (this.media = 1,
this.fdd_state++, this.fdd_state > fddStateEnum.MEDIA_READY && (this.fdd_state = fddStateEnum.MEDIA_READY),
4 === this.event_state && (this.event_state = 0), this.event_state++, this.event_state > 2 && (this.event_state = 2)),
byteArray[0]) {
case SCSI_TEST_UNIT_READY:
this.client_test_unit_ready();
break;
case SCSI_START_STOP_UNIT:
this.client_start_stop_unit(byteArray);
break;
case SCSI_PA_MEDIA_REMOVAL:
this.client_pa_media_removal(byteArray);
break;
case SCSI_READ_CAPACITY:
this.client_read_capacity();
break;
case SCSI_READ_10:
case SCSI_READ_12:
this.client_read(byteArray);
break;
default:
$.log("UNHANDLED SCSI REQUEST: " + byteArray[0]), this.sendRespHeader(5, 36, 0, 0);
}
}, VMconnection.prototype.client_read_capacity = function() {
var sz, data = new Uint8Array(8);
this.fdd_state === fddStateEnum.MEDIA_NOT_PRESENT ? this.sendRespHeader(2, 58, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_CHANGED ? this.sendRespHeader(6, 40, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_READY && (sz = parseInt(this.media_sz / CDROM_SECTOR_SIZE) - 1,
data[0] = sz >> 24 & 255, data[1] = sz >> 16 & 255, data[2] = sz >> 8 & 255, data[3] = sz >> 0 & 255,
data[4] = 0, data[5] = 0, data[6] = 8, data[7] = 0, this.sendRespHeader(0, 0, 0, 8),
this.doSend(data));
}, VMconnection.prototype.client_read = function(cmd) {
var that = this, t = cmd[0] == SCSI_READ_12 ? 1 : 0, offset = VMconnection.mk_int32(cmd, 2) * CDROM_SECTOR_SIZE, length = t ? VMconnection.mk_int32(cmd, 6) : VMconnection.mk_int16(cmd, 7);
length *= CDROM_SECTOR_SIZE;
var reader = new FileReader(), bytesSent = 0, sendBytes = 0;
if (offset >= 0 && offset + length <= this.media_sz || ($.log("offset out of range."),
this.sendRespHeader(5, 33, 0, 0), length = 0), length > 0 && 131072 >= length) {
reader.onloadend = function(e) {
for (that.sendRespHeader(0, 0, 0, length); length > bytesSent; ) {
sendBytes = Math.min(CDROM_MAX_CHUNK_SIZE, length - bytesSent);
var bytes = new Uint8Array(e.target.result.slice(bytesSent, bytesSent + sendBytes));
that.doSend(bytes), bytesSent += sendBytes;
}
}, reader.onerror = function(e) {
$.log("reader.onerror", e), that.sendRespHeader(3, 16, 0, 0);
};
var blob = that.file.slice(offset, offset + length);
reader.readAsArrayBuffer(blob);
} else $.log("Legacy read [not implemented]");
}, VMconnection.prototype.client_start_stop_unit = function(cmd) {
this.sendRespHeader(0, 0, 0, 0), 2 === (3 & cmd[4]) && (this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT,
this.event_state = 4, this.closeVMconnection());
}, VMconnection.prototype.client_pa_media_removal = function(cmd) {
0 !== (1 & cmd[4]), this.sendRespHeader(0, 0, 0, 0);
}, VMconnection.numDevs = 0, VMconnection.mk_int32 = function(cmd, pos) {
var temp0 = cmd[pos + 0], temp1 = cmd[pos + 1], temp2 = cmd[pos + 2], temp3 = cmd[pos + 3], result = (255 & temp0) << 24 | (255 & temp1) << 16 | (255 & temp2) << 8 | 255 & temp3;
return result;
}, VMconnection.mk_int16 = function(cmd, pos) {
var temp0 = cmd[pos + 0], temp1 = cmd[pos + 1], result = (255 & temp0) << 8 | 255 & temp1;
return result;
}, VMconnection.convertNumArrayToHexString = function(list) {
for (var result = [], i = 0; i < list.length; i++) result.push(list[i].toString(16));
return result.join(",");
}, VMconnection_fd.prototype.onMessage = function(evt) {
var currTmrId = this.getTmrId();
if (-1 !== currTmrId && (clearInterval(currTmrId), this.setTmrId(-1)), evt.data instanceof Blob) ; else if (evt.data instanceof ArrayBuffer) {
var byteArray = new Uint8Array(evt.data);
if (4 === evt.data.byteLength) {
var status = byteArray[0], zero = byteArray[1], dlgMsg = "";
if (32 == status && 0 == zero) VMconnection.numDevs++, showIrcToast({
text: iLO.translateString("vm.imgInserted"),
type: "ok",
position: "bottom-right"
}); else {
switch (status) {
case 33:
dlgMsg = iLO.translateString("IRC.error.DriveInUse");
break;
case 34:
dlgMsg = iLO.translateString("IRC.error.InvalidKey");
break;
case 35:
dlgMsg = iLO.translateString("IRC.error.MediaNotLicensed");
break;
case 36:
dlgMsg = iLO.translateString("IRC.error.KeyExpired");
break;
case 37:
dlgMsg = iLO.translateString("IRC.error.DriveNotConfigured");
break;
case 38:
dlgMsg = iLO.translateString("IRC.error.MediaPermitRequired");
break;
default:
dlgMsg = iLO.translateString("IRC.error.CannotConnectDrive");
}
if (dlgMsg.length > 0) {
var msgBox = {
titleKey: "IRC.title.UnableToConnect",
icon: myIcons.critical,
message: dlgMsg,
closeOnClick: !1
};
iLO.alert(msgBox);
}
}
} else 12 === evt.data.byteLength ? this.processSCSIRequest(byteArray) : evt.data.byteLength >= FLOPPY_SECTOR_SIZE && this.client_getWriteData(byteArray);
}
currTmrId = setInterval(this.sendKeepAlive, 2e3), this.setTmrId(currTmrId);
}, VMconnection_fd.prototype.processSCSIRequest = function(byteArray) {
switch (renderer && renderer.onvmactivity && renderer.onvmactivity(), this.media_sz <= 0 ? (this.media = 0,
this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT) : (this.media = 36, this.fdd_state++,
this.fdd_state > fddStateEnum.MEDIA_READY && (this.fdd_state = fddStateEnum.MEDIA_READY)),
byteArray[0]) {
case SCSI_TEST_UNIT_READY:
this.client_test_unit_ready();
break;
case SCSI_START_STOP_UNIT:
this.client_start_stop_unit(byteArray);
break;
case SCSI_PA_MEDIA_REMOVAL:
this.client_pa_media_removal(byteArray);
break;
case SCSI_READ_CAPACITIES:
this.client_read_capacities();
break;
case SCSI_READ_CAPACITY:
this.client_read_capacity();
break;
case SCSI_READ_10:
case SCSI_READ_12:
this.client_read(byteArray);
break;
case SCSI_WRITE_10:
case SCSI_WRITE_12:
this.client_getWriteLen(byteArray);
break;
default:
this.sendRespHeader(5, 36, 0, 0);
}
}, VMconnection_fd.prototype.client_read_capacities = function() {
var sz, rcs_resp = new Uint8Array([ 0, 0, 0, 16, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 11, 64, 0, 0, 2, 0 ]);
this.fdd_state !== fddStateEnum.MEDIA_CHANGED ? this.sendRespHeader(0, 0, 0, rcs_resp.length) : (this.sendRespHeader(6, 40, 0, rcs_resp.length),
this.fdd_state = fddStateEnum.MEDIA_READY), sz = parseInt(this.media_sz / FLOPPY_SECTOR_SIZE),
rcs_resp[4] = sz >> 24 & 255, rcs_resp[5] = sz >> 16 & 255, rcs_resp[6] = sz >> 8 & 255,
rcs_resp[7] = sz >> 0 & 255, rcs_resp[10] = 2, rcs_resp[11] = 0, this.doSend(rcs_resp);
}, VMconnection_fd.prototype.client_read_capacity = function() {
var sz, data = new Uint8Array(8);
this.fdd_state === fddStateEnum.MEDIA_NOT_PRESENT ? this.sendRespHeader(2, 58, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_CHANGED ? this.sendRespHeader(6, 40, 0, 0) : this.fdd_state === fddStateEnum.MEDIA_READY && (sz = parseInt(this.media_sz / FLOPPY_SECTOR_SIZE) - 1,
data[0] = sz >> 24 & 255, data[1] = sz >> 16 & 255, data[2] = sz >> 8 & 255, data[3] = sz >> 0 & 255,
data[6] = 2, this.sendRespHeader(0, 0, 0, 8), this.doSend(data));
}, VMconnection_fd.prototype.client_read = function(cmd) {
var that = this, t = cmd[0] == SCSI_READ_12 ? 1 : 0, offset = VMconnection.mk_int32(cmd, 2) * FLOPPY_SECTOR_SIZE, length = t ? VMconnection.mk_int32(cmd, 6) : VMconnection.mk_int16(cmd, 7);
length *= FLOPPY_SECTOR_SIZE;
var reader = new FileReader(), bytesSent = 0, sendBytes = 0;
if (offset >= 0 && offset < this.media_sz) {
reader.onloadend = function(e) {
for (that.sendRespHeader(0, 0, 0, length); length > bytesSent; ) {
sendBytes = Math.min(FLOPPY_MAX_CHUNK_SIZE, length - bytesSent);
var bytes = new Uint8Array(e.target.result.slice(bytesSent, bytesSent + sendBytes));
that.doSend(bytes), bytesSent += sendBytes;
}
}, reader.onerror = function(e) {
that.sendRespHeader(3, 16, 0, 0);
};
var blob = this.file.slice(offset, offset + length);
reader.readAsArrayBuffer(blob);
} else this.sendRespHeader(5, 33, 0, 0);
}, VMconnection_fd.prototype.client_start_stop_unit = function(cmd) {
this.sendRespHeader(0, 0, 0, 0), 2 === (3 & cmd[4]) && (this.fdd_state = fddStateEnum.MEDIA_NOT_PRESENT,
this.closeVMconnection());
}, VMconnection_fd.prototype.client_pa_media_removal = function(cmd) {
0 !== (2 & cmd[4]) ? this.sendRespHeader(5, 36, 0, 0) : this.sendRespHeader(0, 0, 0, 0);
}, VMconnection_fd.prototype.client_getWriteLen = function(cmd) {
var t = 170 === cmd[0];
this.lba = VMconnection.mk_int32(cmd, 2) * FLOPPY_SECTOR_SIZE, this.writeLen = t ? VMconnection.mk_int32(cmd, 6) : VMconnection.mk_int16(cmd, 7),
this.writeLen *= FLOPPY_SECTOR_SIZE;
}, VMconnection_fd.prototype.client_getWriteData = function(cmd) {
var numRead = cmd.length;
"undefined" == typeof this.client_getWriteData.offset && (this.client_getWriteData.offset = 0);
for (var i = this.client_getWriteData.offset; numRead > i; i++) this.buffer[i] = cmd[i];
this.client_getWriteData.offset += numRead, this.writeLen -= numRead, this.writeLen <= 0 && this.client_fileWrite(this.buffer);
}, VMconnection_fd.prototype.client_fileWrite = function(buffer) {
this.sendRespHeader(0, 0, 0, 0);
};