// Copyright (c) 2015-2016 The Regents of the University of California.
// All rights reserved.
//
// Permission is hereby granted, without written agreement and without
// license or royalty fees, to use, copy, modify, and distribute this
// software and its documentation for any purpose, provided that the above
// copyright notice and the following two paragraphs appear in all copies
// of this software.
//
// IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
// ENHANCEMENTS, OR MODIFICATIONS.
//
/**
* Module supporting UDP (datagram) sockets.
* @module udpSocket
* @author Hokeun Kim and Edward A. Lee
* @version $$Id$$
*/
// Stop extra messages from jslint. Note that there should be no
// space between the / and the * and global.
/*globals Java, actor, exports, require, util */
/*jshint globalstrict: true */
"use strict";
var UDPSocketHelper = Java.type('ptolemy.actor.lib.jjs.modules.udpSocket.UDPSocketHelper');
var EventEmitter = require('events').EventEmitter;
///////////////////////////////////////////////////////////////////////////////
//// createSocket
/** Create a socket of the specified type.
* This returns an instance of the Socket class.
* @param type One of "udp4" or "udp6". Defaults to "udp4" if not given.
* @param callback Optional function to bind to "message" events.
* @param enableBroadcast Boolean to enable broadcasting or not
*/
exports.createSocket = function (type, callback, enableBroadcast) {
if (!type) {
type = "udp4";
}
var socket;
if (enableBroadcast) {
socket = new exports.Socket(type, true);
} else {
socket = new exports.Socket(type, false);
}
if (callback) {
socket.on("message", callback);
}
return socket;
};
///////////////////////////////////////////////////////////////////////////////
//// supportedReceiveTypes
/** Return an array of the types supported by the current host for
* receiveType arguments.
*/
exports.supportedReceiveTypes = function () {
return UDPSocketHelper.supportedReceiveTypes();
};
///////////////////////////////////////////////////////////////////////////////
//// supportedSendTypes
/** Return an array of the types supported by the current host for
* sendType arguments.
*/
exports.supportedSendTypes = function () {
return UDPSocketHelper.supportedSendTypes();
};
///////////////////////////////////////////////////////////////////////////////
//// Socket
/** Construct an instance of a UDP (datagram) socket that can send or receive messages.
* To receive messages, call bind() on the returned object.
* To send messages, call send().
* The returned object is an event emitter that emits
* 'listening', 'message', 'close', or 'error'.
* For example,
* <pre>
* var UDPSocket = require('@accessors-modules/udp-socket');
* var socket = UDPSocket.createSocket();
* socket.on('message', function(message) {
* print('Received from web socket: ' + message);
* });
* socket.bind(8084);
* </pre>
* This class is fashioned after the Socket class in Node's dgram module,
* with the only exception being that the messages it emits are not instances
* of Buffer, but rather appropriate data types as specified by the receiveType
* argument to setReceiveType(). Similarly, the data provided to send() will be
* converted to a Buffer according to the type set by setSendType(). It is also
* possible to deal with the data to send as raw bytes, if setRawBytes is called
* with value true.
*
* @param type One of "udp4" or "udp6", which is ignored in Cape Code.
* @param enableBroadcast boolean, setting to true enables the socket broadcast
* messages.
*/
exports.Socket = function (type, enableBroadcast) {
// FIXME: type is ignored.
var helper = UDPSocketHelper.getOrCreateHelper(actor, this);
if (enableBroadcast) {
this.socket = helper.createSocket(this, true);
} else {
this.socket = helper.createSocket(this, false);
}
};
util.inherits(exports.Socket, EventEmitter);
/** Listen for datagram messages on the specified port and optional address.
* If no port is specified, then attempt to bind to a random port.
* If no address is specified, attempt to listen on all addresses.
* Once binding is complete, a 'listening' event is emitted and the
* optional callback function is called. The value of 'this' in the
* callback invocation will be this Socket object.
* @param port The port to listen on.
* @param address The network interface on which to listen.
* @param callback A function to call when the binding is complete.
*/
exports.Socket.prototype.bind = function (port, address, callback) {
if (!address) {
// FIXME: This assumes udp4?
address = "0.0.0.0";
}
if (!callback) {
callback = null;
}
this.socket.bind(port, address, callback);
};
/** Close the current connection with the server.
* If there is data that was passed to this.send() but has not yet
* been successfully sent (because the socket was not open),
* then throw an exception.
*/
exports.Socket.prototype.close = function () {
this.socket.close();
};
/** Send a datagram message.
* @param data The data to send.
* @param port The destination port.
* @param hostname The name of the destination host (a hostname or IP address).
* @param callback An optional callback function to invoke when the send is complete,
* or if an error occurs. In the latter case, the cause of the error will be passed
* as an argument to the callback.
*/
exports.Socket.prototype.send = function (data, port, hostname, callback) {
if (!callback) {
callback = null;
}
this.socket.send(data, port, hostname, callback);
};
/** Set if the exchanged packets will be considered as raw bytes or not.
* @param value Boolean set set or reset raw byte
*/
exports.Socket.prototype.setRawBytes = function (value) {
this.socket.setRawBytes(value);
};
/** Set the receive type. If this is not called, the type defaults to "string".
* @param type The name of the receive type.
*/
exports.Socket.prototype.setReceiveType = function (type) {
this.socket.setReceiveType(type);
};
/** Set the send type. If this is not called, the type defaults to "string".
* @param type The name of the send type.
*/
exports.Socket.prototype.setSendType = function (type) {
this.socket.setSendType(type);
};