390 lines
17 KiB
JavaScript
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);
|
|
}; |