if (typeof(JS_LIB_LOADED)=='boolean') { const JS_SOCKET_FILE = "socket.js"; const JS_SOCKET_LOADED = true; function Socket () { if (arguments.length) this.init(arguments[0]); else this.init(); } /** * function: available * purpose: number of bytes waiting to be read * * interface: available() * * returns: integer : number of bytes waiting to be read */ Socket.prototype.available = function () { if (!this.isAlive()) return 0; var bytesAvailable = 0; try { bytesAvailable = this._inputInterface.available(); } catch(exception) { this.isConnected = false; this._exception = exception; } return bytesAvailable; } /** * function: close * purpose: closes the socket connection * interface: close() * * returns: nothing. */ Socket.prototype.close = function () { if (!this.isOpen()) return; this.isOpenFlag = false; this.isConnected = false; // calls to _inputStream.close() and _outputStream.close() didn't // function. this._transport.close(0); } /** * function: init * purpose: provides initialization for the Socket class. * interface: socket([classID]) * arguments: classID : classesByID class-identifier (see Socket for info) * returns: nothing. */ Socket.prototype.init = function () { this.isOpenFlag = false; this.isConnected = false; this.openInputFlags = 0; this.openInputSegmentSize = 0; this.openInputSegmentCount = 0; this.openOutputFlags = 0; this.openOutputSegmentSize = 0; this.openOutputSegmentCount = 0; var defaultContractID = "@mozilla.org/network/socket-transport-service;1"; // var defaultClassID = "{c07e81e0-ef12-11d2-92b6-00105a1b0d64}" var socketServiceClass; switch (arguments.length) { case 0: socketServiceClass = C.classes[defaultContractID]; break; case 1: socketServiceClass = C.classesByID[arguments[0]]; break; default: throw( "Socket.init: unexpected arguments" ); break; } if (!socketServiceClass) throw ("Socket constructor: Couldn't get socket service class."); var socketService = socketServiceClass.getService(); if (!socketService) throw ("Socket constructor: Couldn't get socket service."); this._socketService = jslibQI(socketService, "nsISocketTransportService"); } /** * function: isAlive * purpose: tests the connection to see if it still works. * interface: isAlive() * arguments: none. * returns: boolean : true if the connection still works. * * Note: * This function is not accurate if invoked in the same javascript * stack crawl as open(). */ Socket.prototype.isAlive = function () { this.isConnected = ( this.isOpen() ? this._transport.isAlive() : false ); return this.isConnected; } /** * function: isOpen * purpose: returns true if the socket has been opened (which is * different from connect). Multiple invocations of open will * fail if each old connection is not closed first. * interface: isOpen() * arguments: none. * returns: boolean : true if open() has been invoked without close. */ Socket.prototype.isOpen = function () { return this.isOpenFlag; } /** * function: open * purpose: opens the socket * interface: open( host, port [ binary ] ) * * arguments: host : String, host to connect to * port : int, port number to use * binary : optional, use binary input support, defaults false * * returns: nothing. */ Socket.prototype.open = function (host, port) { if (this.isOpen()) return; this.host = host.toLowerCase(); this.port = port; this.binary = (arguments.length > 2) ? arguments[ 2 ] : false; this.isOpenFlag = true; // in theory, we'd look up proxy information here. but we're being // a bare socket so.... // create the transport: // socketTypes = null // typeCount = 0 // host // port // proxy-info = null this._transport = this._socketService.createTransport(null, 0, host, port, null); if (!this._transport) throw ("Socket.open: Error opening transport."); var openFlags = (this.blocking ) && ( typeof document == "object") ? 0 : C.interfaces.nsITransport.OPEN_BLOCKING; this._inputStream = this._transport.openInputStream( this.openInputFlags, this.openInputSegmentSize, this.openInputSegmentCount); if (!this._inputStream) throw ("Socket.open: Error getting input stream."); if (this.binary) this._inputInterface = this.toBinaryInputStream( this._inputStream ); else this._inputInterface = this.toScriptableInputStream( this._inputStream ); this._outputStream = this._transport.openOutputStream( this.openOutputFlags, this.openOutputSegmentSize, this.openOutputSegmentCount ); if (!this._outputStream) throw ("Socket.open: Error getting output stream."); // We really should call _transport.isAlive (?) but that is never reliable // (either always false or always true). // Experimentation shows that calls to available() or isAlive() will not // catch any problems with the connection until the javascript call // stack has completely unwound. this.isConnected = true; } /** * function: read * purpose: reads data from a socket. * * interface: read(bytes) * * arguments: bytes : integer, number of bytes to read in * * returns: string * * Note: * will only return the smaller of specified vs available bytes. * */ Socket.prototype.read = function (bytes) { if (!this.isAlive()) throw "Socket.read: Not Connected."; var rv = new String; if (bytes == 0) return rv; var availableBytes = this.available(); if (availableBytes == 0) return rv; bytes = Math.min(availableBytes, bytes); if (bytes) { if (this.binary) // despite the documentation, this call works rv = this._inputInterface.readBytes( bytes ); else rv = this._inputInterface.read( bytes ); } return rv; } /** * function: write * purpose: writes the given string to the socket. * * interface: write(str) * * arguments: str : string to be written. * * returns: integer : number of bytes written. */ Socket.prototype.write = function (str) { if (!this.isAlive()) throw "Socket.write: Not Connected."; var rv = 0; try { rv = this._outputStream.write(str, str.length); } catch (e) { this.isConnected = false; } return rv; } /* * function: toBinaryInputStream * purpose: creates an nsIBinaryInputStream wrapper around the given * inputStream. * * interface: toBinaryInputStream(inputStream) * * arguments: inputStream : result of openInputStream * * returns: nsIBinaryInputStream */ Socket.prototype.toBinaryInputStream = function (inputStream) { var rv = jslibCreateInstance("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream"); rv.setInputStream(inputStream); return rv; } /** * function: toScriptableInputStream * purpose: creates an nsIScriptableInputStream wrapper around the given * inputStream. * * interface: toScriptableInputStream( inputStream ) * * arguments: inputStream : result of openInputStream * * returns: nsIScriptableInputStream */ Socket.prototype.toScriptableInputStream = function (inputStream) { var rv = jslibCreateInstance("@mozilla.org/scriptableinputstream;1", "nsIScriptableInputStream"); rv.init( inputStream ); return rv; } /** * function: async * purpose: * interface: * * returns: * usage: * * var aSocket = new Socket; * var observer = { * streamStarted: function (socketContext){ }, //onstart action * streamStopped: function (socketContext, status){ }, //onstop action * receiveData: function (data){alert(data)} * } * aSocket.open("ftp.mozilla.org", 21); * aSocket.async(observer ); * */ Socket.prototype.async = function (observer) { // to preserve ourselves within necko/async this.wrappedJSObject = this; this._pump = jslibCreateInstance("@mozilla.org/network/input-stream-pump;1", "nsIInputStreamPump"); this._pump.init(this._inputStream, -1, -1, 0, 0, false); this._pump.asyncRead(new SocketListener(observer), this); } // async callbacks function SocketListener(observer) { this._observer = observer; } SocketListener.prototype.onStartRequest = function (channel, socketContext) { theSocket = socketContext.wrappedJSObject; this._observer.streamStarted( theSocket ); } SocketListener.prototype.onStopRequest = function (channel, socketContext, status, errorMsg) { theSocket = socketContext.wrappedJSObject; this._observer.streamStopped( theSocket, status ); } SocketListener.prototype.onDataAvailable = function (channel, socketContext, inputStream, sourceOffset, count) { theSocket = socketContext.wrappedJSObject; // try and maintain the connection // but read here because Socket.read will fail with HTTP requests due // to the socket being closed. theSocket._inputStream = inputStream; if (theSocket.binary) { theSocket._inputInterface = theSocket.toBinaryInputStream( theSocket._inputStream ); // despite the documentation, readBytes works this._observer.receiveData( theSocket._inputInterface.readBytes(count) ); } else { theSocket._inputInterface = theSocket.toScriptableInputStream( theSocket._inputStream ); this._observer.receiveData( theSocket._inputInterface.read(count) ); } } jslibLoadMsg(JS_SOCKET_FILE); } else { dump("Load Failure: socket.js\n"); }