jl777
9 years ago
338 changed files with 55897 additions and 276 deletions
@ -0,0 +1,605 @@ |
|||||
|
<!DOCTYPE HTML> |
||||
|
<html style="overflow-y:scroll;-webkit-user-select: text"> |
||||
|
<head> |
||||
|
<meta http-equiv="Pragma" content="no-cache"> |
||||
|
<meta http-equiv="Expires" content="-1"> |
||||
|
<title>InstantDEX</title> |
||||
|
</head> |
||||
|
<body data-custom-load="true" data-name="InstantDEX" data-tools="pnacl newlib glibc clang-newlib mac" data-configs="Debug Release" data-path="{tc}/{config}"> |
||||
|
<div class="debuglog" hidden> |
||||
|
<pre id="log" style="font-weight: bold"></pre> |
||||
|
</div> |
||||
|
<div id="listener"></div> |
||||
|
<script type="text/javascript"> |
||||
|
var isTest = false; |
||||
|
var isRelease = true; |
||||
|
// Javascript module pattern: |
||||
|
// see http://en.wikipedia.org/wiki/Unobtrusive_JavaScript#Namespaces |
||||
|
// In essence, we define an anonymous function which is immediately called and |
||||
|
// returns a new object. The new object contains only the exported definitions; |
||||
|
// all other definitions in the anonymous function are inaccessible to external |
||||
|
// code. |
||||
|
var common = (function() { |
||||
|
|
||||
|
function isHostToolchain(tool) { |
||||
|
return tool == 'win' || tool == 'linux' || tool == 'mac'; |
||||
|
} |
||||
|
function mimeTypeForTool(tool) { |
||||
|
// For NaCl modules use application/x-nacl. |
||||
|
var mimetype = 'application/x-nacl'; |
||||
|
if (isHostToolchain(tool)) { |
||||
|
// For non-NaCl PPAPI plugins use the x-ppapi-debug/release |
||||
|
// mime type. |
||||
|
if (isRelease) |
||||
|
mimetype = 'application/x-ppapi-release'; |
||||
|
else |
||||
|
mimetype = 'application/x-ppapi-debug'; |
||||
|
} else if (tool == 'pnacl') { |
||||
|
mimetype = 'application/x-pnacl'; |
||||
|
} |
||||
|
return mimetype; |
||||
|
} |
||||
|
function browserSupportsNaCl(tool) { |
||||
|
// Assume host toolchains always work with the given browser. |
||||
|
// The below mime-type checking might not work with |
||||
|
// --register-pepper-plugins. |
||||
|
if (isHostToolchain(tool)) { |
||||
|
return true; |
||||
|
} |
||||
|
var mimetype = mimeTypeForTool(tool); |
||||
|
return navigator.mimeTypes[mimetype] !== undefined; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Inject a script into the DOM, and call a callback when it is loaded. |
||||
|
* |
||||
|
* @param {string} url The url of the script to load. |
||||
|
* @param {Function} onload The callback to call when the script is loaded. |
||||
|
* @param {Function} onerror The callback to call if the script fails to load. |
||||
|
*/ |
||||
|
function injectScript(url, onload, onerror) { |
||||
|
var scriptEl = document.createElement('script'); |
||||
|
scriptEl.type = 'text/javascript'; |
||||
|
scriptEl.src = url; |
||||
|
scriptEl.onload = onload; |
||||
|
if (onerror) { |
||||
|
scriptEl.addEventListener('error', onerror, false); |
||||
|
} |
||||
|
document.head.appendChild(scriptEl); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Run all tests for this example. |
||||
|
* |
||||
|
* @param {Object} moduleEl The module DOM element. |
||||
|
*/ |
||||
|
function runTests(moduleEl) { |
||||
|
console.log('runTests()'); |
||||
|
common.tester = new Tester(); |
||||
|
|
||||
|
// All NaCl SDK examples are OK if the example exits cleanly; (i.e. the |
||||
|
// NaCl module returns 0 or calls exit(0)). |
||||
|
// |
||||
|
// Without this exception, the browser_tester thinks that the module has crashed. |
||||
|
common.tester.exitCleanlyIsOK(); |
||||
|
|
||||
|
common.tester.addAsyncTest('loaded', function(test) { |
||||
|
test.pass(); |
||||
|
}); |
||||
|
|
||||
|
if (typeof window.addTests !== 'undefined') { |
||||
|
window.addTests(); |
||||
|
} |
||||
|
|
||||
|
common.tester.waitFor(moduleEl); |
||||
|
common.tester.run(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Create the Native Client <embed> element as a child of the DOM element |
||||
|
* named "listener". |
||||
|
* |
||||
|
* @param {string} name The name of the example. |
||||
|
* @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc. |
||||
|
* @param {string} path Directory name where .nmf file can be found. |
||||
|
* @param {number} width The width to create the plugin. |
||||
|
* @param {number} height The height to create the plugin. |
||||
|
* @param {Object} attrs Dictionary of attributes to set on the module. |
||||
|
*/ |
||||
|
function createNaClModule(name, tool, path, width, height, attrs) { |
||||
|
var moduleEl = document.createElement('embed'); |
||||
|
moduleEl.setAttribute('name', 'nacl_module'); |
||||
|
moduleEl.setAttribute('id', 'nacl_module'); |
||||
|
moduleEl.setAttribute('width', width); |
||||
|
moduleEl.setAttribute('height', height); |
||||
|
moduleEl.setAttribute('path', path); |
||||
|
moduleEl.setAttribute('src', path + '/' + name + '.nmf'); |
||||
|
|
||||
|
// Add any optional arguments |
||||
|
if (attrs) { |
||||
|
for (var key in attrs) { |
||||
|
moduleEl.setAttribute(key, attrs[key]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var mimetype = mimeTypeForTool(tool); |
||||
|
moduleEl.setAttribute('type', mimetype); |
||||
|
|
||||
|
// The <EMBED> element is wrapped inside a <DIV>, which has both a 'load' |
||||
|
// and a 'message' event listener attached. This wrapping method is used |
||||
|
// instead of attaching the event listeners directly to the <EMBED> element |
||||
|
// to ensure that the listeners are active before the NaCl module 'load' |
||||
|
// event fires. |
||||
|
var listenerDiv = document.getElementById('listener'); |
||||
|
listenerDiv.appendChild(moduleEl); |
||||
|
|
||||
|
// Request the offsetTop property to force a relayout. As of Apr 10, 2014 |
||||
|
// this is needed if the module is being loaded on a Chrome App's |
||||
|
// background page (see crbug.com/350445). |
||||
|
moduleEl.offsetTop; |
||||
|
|
||||
|
// Host plugins don't send a moduleDidLoad message. We'll fake it here. |
||||
|
var isHost = isHostToolchain(tool); |
||||
|
if (isHost) { |
||||
|
window.setTimeout(function() { |
||||
|
moduleEl.readyState = 1; |
||||
|
moduleEl.dispatchEvent(new CustomEvent('loadstart')); |
||||
|
moduleEl.readyState = 4; |
||||
|
moduleEl.dispatchEvent(new CustomEvent('load')); |
||||
|
moduleEl.dispatchEvent(new CustomEvent('loadend')); |
||||
|
}, 100); // 100 ms |
||||
|
} |
||||
|
|
||||
|
// This is code that is only used to test the SDK. |
||||
|
if (isTest) { |
||||
|
var loadNaClTest = function() { |
||||
|
injectScript('nacltest.js', function() { |
||||
|
runTests(moduleEl); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// Try to load test.js for the example. Whether or not it exists, load |
||||
|
// nacltest.js. |
||||
|
injectScript('test.js', loadNaClTest, loadNaClTest); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Add the default "load" and "message" event listeners to the element with |
||||
|
* id "listener". |
||||
|
* |
||||
|
* The "load" event is sent when the module is successfully loaded. The |
||||
|
* "message" event is sent when the naclModule posts a message using |
||||
|
* PPB_Messaging.PostMessage() (in C) or pp::Instance().PostMessage() (in |
||||
|
* C++). |
||||
|
*/ |
||||
|
function attachDefaultListeners() { |
||||
|
var listenerDiv = document.getElementById('listener'); |
||||
|
listenerDiv.addEventListener('load', moduleDidLoad, true); |
||||
|
listenerDiv.addEventListener('message', handleMessage, true); |
||||
|
listenerDiv.addEventListener('error', handleError, true); |
||||
|
listenerDiv.addEventListener('crash', handleCrash, true); |
||||
|
if (typeof window.attachListeners !== 'undefined') { |
||||
|
window.attachListeners(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Called when the NaCl module fails to load. |
||||
|
* |
||||
|
* This event listener is registered in createNaClModule above. |
||||
|
*/ |
||||
|
function handleError(event) { |
||||
|
// We can't use common.naclModule yet because the module has not been |
||||
|
// loaded. |
||||
|
var moduleEl = document.getElementById('nacl_module'); |
||||
|
updateStatus('ERROR [' + moduleEl.lastError + ']'); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Called when the Browser can not communicate with the Module |
||||
|
* |
||||
|
* This event listener is registered in attachDefaultListeners above. |
||||
|
*/ |
||||
|
function handleCrash(event) { |
||||
|
if (common.naclModule.exitStatus != 0) { |
||||
|
updateStatus('ABORTED [' + common.naclModule.exitStatus + ']'); |
||||
|
} else { |
||||
|
updateStatus('EXITED [' + common.naclModule.exitStatus + ']'); |
||||
|
} |
||||
|
if (typeof window.handleCrash !== 'undefined') { |
||||
|
window.handleCrash(common.naclModule.lastError); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Called when the NaCl module is loaded. |
||||
|
* |
||||
|
* This event listener is registered in attachDefaultListeners above. |
||||
|
*/ |
||||
|
function moduleDidLoad() { |
||||
|
common.naclModule = document.getElementById('nacl_module'); |
||||
|
updateStatus('RUNNING'); |
||||
|
|
||||
|
if (typeof window.moduleDidLoad !== 'undefined') { |
||||
|
window.moduleDidLoad(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Hide the NaCl module's embed element. |
||||
|
* |
||||
|
* We don't want to hide by default; if we do, it is harder to determine that |
||||
|
* a plugin failed to load. Instead, call this function inside the example's |
||||
|
* "moduleDidLoad" function. |
||||
|
* |
||||
|
*/ |
||||
|
function hideModule() { |
||||
|
// Setting common.naclModule.style.display = "None" doesn't work; the |
||||
|
// module will no longer be able to receive postMessages. |
||||
|
common.naclModule.style.height = '0'; |
||||
|
} |
||||
|
function removeModule() { |
||||
|
common.naclModule.parentNode.removeChild(common.naclModule); |
||||
|
common.naclModule = null; |
||||
|
} |
||||
|
function startsWith(s, prefix) { |
||||
|
// indexOf would search the entire string, lastIndexOf(p, 0) only checks at |
||||
|
// the first index. See: http://stackoverflow.com/a/4579228 |
||||
|
return s.lastIndexOf(prefix, 0) === 0; |
||||
|
} |
||||
|
var kMaxLogMessageLength = 777; |
||||
|
var logMessageArray = []; |
||||
|
function logMessage(message) { |
||||
|
logMessageArray.push(message); |
||||
|
if ( logMessageArray.length > kMaxLogMessageLength ) |
||||
|
logMessageArray.shift(); |
||||
|
|
||||
|
var node = document.createElement("div"); // Create a node |
||||
|
var textnode = document.createTextNode(message); // Create a text node |
||||
|
node.appendChild(textnode); // Append the text to <li> |
||||
|
document.getElementById("log").appendChild(node); |
||||
|
|
||||
|
//document.getElementById('log').appendChild(message); |
||||
|
console.log(message); |
||||
|
} |
||||
|
var defaultMessageTypes = { |
||||
|
'alert': alert, |
||||
|
'log': logMessage |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Called when the NaCl module sends a message to JavaScript (via |
||||
|
* PPB_Messaging.PostMessage()) |
||||
|
* |
||||
|
* This event listener is registered in createNaClModule above. |
||||
|
* |
||||
|
* @param {Event} message_event A message event. message_event.data contains |
||||
|
* the data sent from the NaCl module. |
||||
|
*/ |
||||
|
|
||||
|
function retmsg(msg) |
||||
|
{ |
||||
|
common.naclModule.postMessage(msg); |
||||
|
console.log("sent: "+msg); |
||||
|
} |
||||
|
|
||||
|
function handleMessage(message_event) |
||||
|
{ |
||||
|
if (typeof message_event.data === 'string') { |
||||
|
for (var type in defaultMessageTypes) { |
||||
|
if (defaultMessageTypes.hasOwnProperty(type)) { |
||||
|
if (startsWith(message_event.data, type + ':')) { |
||||
|
func = defaultMessageTypes[type]; |
||||
|
func(message_event.data.slice(type.length + 1)); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (typeof window.handleMessage !== 'undefined') { |
||||
|
window.handleMessage(message_event); |
||||
|
return; |
||||
|
} |
||||
|
logMessage('Unhandled message: ' + message_event.data); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Called when the DOM content has loaded; i.e. the page's document is fully |
||||
|
* parsed. At this point, we can safely query any elements in the document via |
||||
|
* document.querySelector, document.getElementById, etc. |
||||
|
* |
||||
|
* @param {string} name The name of the example. |
||||
|
* @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc. |
||||
|
* @param {string} path Directory name where .nmf file can be found. |
||||
|
* @param {number} width The width to create the plugin. |
||||
|
* @param {number} height The height to create the plugin. |
||||
|
* @param {Object} attrs Optional dictionary of additional attributes. |
||||
|
*/ |
||||
|
function domContentLoaded(name, tool, path, width, height, attrs) { |
||||
|
// If the page loads before the Native Client module loads, then set the |
||||
|
// status message indicating that the module is still loading. Otherwise, |
||||
|
// do not change the status message. |
||||
|
updateStatus('Page loaded.'); |
||||
|
if (!browserSupportsNaCl(tool)) { |
||||
|
updateStatus( |
||||
|
'Browser does not support NaCl (' + tool + '), or NaCl is disabled'); |
||||
|
} else if (common.naclModule == null) { |
||||
|
updateStatus('Creating embed: ' + tool); |
||||
|
|
||||
|
// We use a non-zero sized embed to give Chrome space to place the bad |
||||
|
// plug-in graphic, if there is a problem. |
||||
|
width = typeof width !== 'undefined' ? width : 200; |
||||
|
height = typeof height !== 'undefined' ? height : 200; |
||||
|
attachDefaultListeners(); |
||||
|
createNaClModule(name, tool, path, width, height, attrs); |
||||
|
} else { |
||||
|
// It's possible that the Native Client module onload event fired |
||||
|
// before the page's onload event. In this case, the status message |
||||
|
// will reflect 'SUCCESS', but won't be displayed. This call will |
||||
|
// display the current message. |
||||
|
updateStatus('Waiting.'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** Saved text to display in the element with id 'statusField'. */ |
||||
|
var statusText = 'NO-STATUSES'; |
||||
|
|
||||
|
/** |
||||
|
* Set the global status message. If the element with id 'statusField' |
||||
|
* exists, then set its HTML to the status message as well. |
||||
|
* |
||||
|
* @param {string} opt_message The message to set. If null or undefined, then |
||||
|
* set element 'statusField' to the message from the last call to |
||||
|
* updateStatus. |
||||
|
*/ |
||||
|
function updateStatus(opt_message) { |
||||
|
if (opt_message) { |
||||
|
statusText = opt_message; |
||||
|
} |
||||
|
var statusField = document.getElementById('statusField'); |
||||
|
if (statusField) { |
||||
|
statusField.innerHTML = statusText; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// The symbols to export. |
||||
|
return { |
||||
|
/** A reference to the NaCl module, once it is loaded. */ |
||||
|
naclModule: null, |
||||
|
|
||||
|
attachDefaultListeners: attachDefaultListeners, |
||||
|
domContentLoaded: domContentLoaded, |
||||
|
createNaClModule: createNaClModule, |
||||
|
hideModule: hideModule, |
||||
|
removeModule: removeModule, |
||||
|
logMessage: logMessage, |
||||
|
updateStatus: updateStatus |
||||
|
}; |
||||
|
|
||||
|
}()); |
||||
|
|
||||
|
// Listen for the DOM content to be loaded. This event is fired when parsing of |
||||
|
// the page's document has finished. |
||||
|
document.addEventListener('DOMContentLoaded', function() { |
||||
|
|
||||
|
var body = document.body; |
||||
|
|
||||
|
// The data-* attributes on the body can be referenced via body.dataset. |
||||
|
if (body.dataset) { |
||||
|
var loadFunction; |
||||
|
if (!body.dataset.customLoad) { |
||||
|
loadFunction = common.domContentLoaded; |
||||
|
} else if (typeof window.domContentLoaded !== 'undefined') { |
||||
|
loadFunction = window.domContentLoaded; |
||||
|
} |
||||
|
|
||||
|
// From https://developer.mozilla.org/en-US/docs/DOM/window.location |
||||
|
var searchVars = {}; |
||||
|
if (window.location.search.length > 1) { |
||||
|
var pairs = window.location.search.substr(1).split('&'); |
||||
|
for (var key_ix = 0; key_ix < pairs.length; key_ix++) { |
||||
|
var keyValue = pairs[key_ix].split('='); |
||||
|
searchVars[unescape(keyValue[0])] = |
||||
|
keyValue.length > 1 ? unescape(keyValue[1]) : ''; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (loadFunction) { |
||||
|
var toolchains = body.dataset.tools.split(' '); |
||||
|
var configs = body.dataset.configs.split(' '); |
||||
|
|
||||
|
var attrs = {}; |
||||
|
if (body.dataset.attrs) { |
||||
|
var attr_list = body.dataset.attrs.split(' '); |
||||
|
for (var key in attr_list) { |
||||
|
var attr = attr_list[key].split('='); |
||||
|
var key = attr[0]; |
||||
|
var value = attr[1]; |
||||
|
attrs[key] = value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var tc = toolchains.indexOf(searchVars.tc) !== -1 ? |
||||
|
searchVars.tc : toolchains[0]; |
||||
|
|
||||
|
// If the config value is included in the search vars, use that. |
||||
|
// Otherwise default to Release if it is valid, or the first value if |
||||
|
// Release is not valid. |
||||
|
if (configs.indexOf(searchVars.config) !== -1) |
||||
|
var config = searchVars.config; |
||||
|
else if (configs.indexOf('Release') !== -1) |
||||
|
var config = 'Release'; |
||||
|
else |
||||
|
var config = configs[0]; |
||||
|
|
||||
|
var pathFormat = body.dataset.path; |
||||
|
var path = pathFormat.replace('{tc}', tc).replace('{config}', config); |
||||
|
|
||||
|
isTest = searchVars.test === 'true'; |
||||
|
isRelease = path.toLowerCase().indexOf('release') != -1; |
||||
|
|
||||
|
loadFunction(body.dataset.name, tc, path, body.dataset.width, |
||||
|
body.dataset.height, attrs); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
</script> |
||||
|
<script type="text/javascript"> |
||||
|
function moduleDidLoad() { |
||||
|
common.hideModule(); |
||||
|
} |
||||
|
|
||||
|
function $(id) { |
||||
|
return document.getElementById(id); |
||||
|
} |
||||
|
|
||||
|
// Called by the common.js module. |
||||
|
function domContentLoaded(name, tc, config, width, height) { |
||||
|
navigator.webkitPersistentStorage.requestQuota(10000000000, |
||||
|
function(bytes) { |
||||
|
common.updateStatus( |
||||
|
'Allocated ' + bytes + ' bytes of persistent storage. Running the first time will take 17 seconds to load'); |
||||
|
common.attachDefaultListeners(); |
||||
|
common.createNaClModule(name, tc, config, width, height); |
||||
|
}, |
||||
|
function(e) { alert('Failed to allocate space') }); |
||||
|
} |
||||
|
|
||||
|
// Called by the common.js module. |
||||
|
function attachListeners() { |
||||
|
var radioEls = document.querySelectorAll('input[type="radio"]'); |
||||
|
for (var i = 0; i < radioEls.length; ++i) { |
||||
|
radioEls[i].addEventListener('click', onRadioClicked); |
||||
|
} |
||||
|
|
||||
|
// Wire up the 'click' event for each function's button. |
||||
|
var functionEls = document.querySelectorAll('.function'); |
||||
|
for (var i = 0; i < functionEls.length; ++i) { |
||||
|
var functionEl = functionEls[i]; |
||||
|
var id = functionEl.getAttribute('id'); |
||||
|
var buttonEl = functionEl.querySelector('button'); |
||||
|
|
||||
|
// The function name matches the element id. |
||||
|
var func = window[id]; |
||||
|
buttonEl.addEventListener('click', func); |
||||
|
} |
||||
|
//$('pipe_input_box').addEventListener('keypress', onPipeInput) |
||||
|
//$('pipe_output').disabled = true; |
||||
|
//$('pipe_name').addEventListener('change', function() { $('pipe_output').value = ''; }) |
||||
|
} |
||||
|
|
||||
|
// Called with keypress events on the pipe input box |
||||
|
function onPipeInput(e) { |
||||
|
// Create an arraybuffer containing the 16-bit char code |
||||
|
// from the keypress event. |
||||
|
var buffer = new ArrayBuffer(1*2); |
||||
|
var bufferView = new Uint16Array(buffer); |
||||
|
bufferView[0] = e.charCode; |
||||
|
|
||||
|
// Pass the buffer in a dictionary over the NaCl module |
||||
|
var pipeSelect = $('pipe_name'); |
||||
|
var pipeName = pipeSelect[pipeSelect.selectedIndex].value; |
||||
|
var message = { |
||||
|
pipe: pipeName, |
||||
|
operation: 'write', |
||||
|
payload: buffer, |
||||
|
}; |
||||
|
nacl_module.postMessage(message); |
||||
|
e.preventDefault(); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
function onRadioClicked(e) { |
||||
|
var divId = this.id.slice(5); // skip "radio" |
||||
|
var functionEls = document.querySelectorAll('.function'); |
||||
|
for (var i = 0; i < functionEls.length; ++i) { |
||||
|
var visible = functionEls[i].id === divId; |
||||
|
if (functionEls[i].id === divId) |
||||
|
functionEls[i].removeAttribute('hidden'); |
||||
|
else |
||||
|
functionEls[i].setAttribute('hidden', ''); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function addNameToSelectElements(cssClass, handle, name) { |
||||
|
var text = '[' + handle + '] ' + name; |
||||
|
var selectEls = document.querySelectorAll(cssClass); |
||||
|
for (var i = 0; i < selectEls.length; ++i) { |
||||
|
var optionEl = document.createElement('option'); |
||||
|
optionEl.setAttribute('value', handle); |
||||
|
optionEl.appendChild(document.createTextNode(text)); |
||||
|
selectEls[i].appendChild(optionEl); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function removeNameFromSelectElements(cssClass, handle) { |
||||
|
var optionEls = document.querySelectorAll(cssClass + ' > option'); |
||||
|
for (var i = 0; i < optionEls.length; ++i) { |
||||
|
var optionEl = optionEls[i]; |
||||
|
if (optionEl.value == handle) { |
||||
|
var selectEl = optionEl.parentNode; |
||||
|
selectEl.removeChild(optionEl); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var funcToCallback = {}; |
||||
|
|
||||
|
function postCall(func) { |
||||
|
var callback = arguments[arguments.length - 1]; |
||||
|
funcToCallback[func] = callback; |
||||
|
|
||||
|
nacl_module.postMessage({ |
||||
|
cmd: func, |
||||
|
args: Array.prototype.slice.call(arguments, 1, -1) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function ArrayBufferToString(buf) { return String.fromCharCode.apply(null, new Uint16Array(buf)); } |
||||
|
|
||||
|
// Called by the common.js module. |
||||
|
function handleMessage(message_event) { |
||||
|
var data = message_event.data; |
||||
|
if ((typeof(data) === 'string' || data instanceof String)) { |
||||
|
common.logMessage(data); |
||||
|
} |
||||
|
else if (data instanceof Object) |
||||
|
{ |
||||
|
var pipeName = data['pipe'] |
||||
|
if ( pipeName !== undefined ) |
||||
|
{ |
||||
|
// Message for JavaScript I/O pipe |
||||
|
var operation = data['operation']; |
||||
|
if (operation == 'write') { |
||||
|
$('pipe_output').value += ArrayBufferToString(data['payload']); |
||||
|
} else if (operation == 'ack') { |
||||
|
common.logMessage(pipeName + ": ack:" + data['payload']); |
||||
|
} else { |
||||
|
common.logMessage('Got unexpected pipe operation: ' + operation); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// Result from a function call. |
||||
|
var params = data.args; |
||||
|
var funcName = data.cmd; |
||||
|
var callback = funcToCallback[funcName]; |
||||
|
if (!callback) |
||||
|
{ |
||||
|
common.logMessage('Error: Bad message ' + funcName + ' received from NaCl module.'); |
||||
|
return; |
||||
|
} |
||||
|
delete funcToCallback[funcName]; |
||||
|
callback.apply(null, params); |
||||
|
} |
||||
|
} else { |
||||
|
common.logMessage('Error: Unknow message `' + data + '` received from NaCl module.'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,68 @@ |
|||||
|
/******************************************************************************
|
||||
|
* Copyright © 2014-2015 The SuperNET Developers. * |
||||
|
* * |
||||
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
||||
|
* the top-level directory of this distribution for the individual copyright * |
||||
|
* holder information and the developer policies on copyright and licensing. * |
||||
|
* * |
||||
|
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
||||
|
* SuperNET software, including this file may be copied, modified, propagated * |
||||
|
* or distributed except according to the terms contained in the LICENSE file * |
||||
|
* * |
||||
|
* Removal or modification of this copyright notice is prohibited. * |
||||
|
* * |
||||
|
******************************************************************************/ |
||||
|
|
||||
|
#ifndef INCLUDED_SUPERNET_H |
||||
|
#define INCLUDED_SUPERNET_H |
||||
|
|
||||
|
#include "../crypto777/OS_portable.h" |
||||
|
#include "../includes/cJSON.h" |
||||
|
#include "../includes/nanomsg/nn.h" |
||||
|
|
||||
|
#define SUPERNET_PORT 7774 |
||||
|
#define SUPERNET_TIMEOUT 10000 |
||||
|
#define SUPERNET_MAXPEERS 128 |
||||
|
|
||||
|
#define LB_OFFSET 1 |
||||
|
#define PUBGLOBALS_OFFSET 2 |
||||
|
#define PUBRELAYS_OFFSET 3 |
||||
|
#define SUPERNET_APIENDPOINT "tcp://127.0.0.1:7776"
|
||||
|
#define NXT_TOKEN_LEN 160 |
||||
|
|
||||
|
#define nn_errstr() nn_strerror(nn_errno()) |
||||
|
|
||||
|
#define CONNECTION_NUMBITS 10 |
||||
|
struct endpoint { uint64_t ipbits:32,port:16,transport:2,nn:4,directind:CONNECTION_NUMBITS; }; |
||||
|
|
||||
|
#define MAX_SERVERNAME 128 |
||||
|
struct relayargs |
||||
|
{ |
||||
|
char name[16],endpoint[MAX_SERVERNAME]; |
||||
|
int32_t sock,type,bindflag,sendtimeout,recvtimeout; |
||||
|
}; |
||||
|
|
||||
|
struct relay_info { int32_t sock,num,mytype,desttype; struct endpoint connections[1 << CONNECTION_NUMBITS]; }; |
||||
|
struct direct_connection { char handler[16]; struct endpoint epbits; int32_t sock; }; |
||||
|
|
||||
|
struct supernet_info |
||||
|
{ |
||||
|
char ipaddr[64],transport[8]; int32_t APISLEEP; int32_t iamrelay; uint64_t my64bits; uint64_t ipbits; |
||||
|
int32_t Debuglevel,readyflag,dead; |
||||
|
int32_t pullsock,subclient,lbclient,lbserver,servicesock,pubglobal,pubrelays,numservers; |
||||
|
uint16_t port,serviceport,portp2p; |
||||
|
struct nn_pollfd pfd[16]; struct relay_info active; |
||||
|
}; |
||||
|
|
||||
|
void expand_epbits(char *endpoint,struct endpoint epbits); |
||||
|
struct endpoint calc_epbits(char *transport,uint32_t ipbits,uint16_t port,int32_t type); |
||||
|
|
||||
|
int32_t badass_servers(char servers[][MAX_SERVERNAME],int32_t max,int32_t port); |
||||
|
int32_t crackfoo_servers(char servers[][MAX_SERVERNAME],int32_t max,int32_t port); |
||||
|
void SuperNET_init(); |
||||
|
|
||||
|
extern int32_t PULLsock; |
||||
|
extern struct relay_info RELAYS; |
||||
|
|
||||
|
#endif |
||||
|
|
File diff suppressed because it is too large
@ -0,0 +1,332 @@ |
|||||
|
/******************************************************************************
|
||||
|
* Copyright © 2014-2015 The SuperNET Developers. * |
||||
|
* * |
||||
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
||||
|
* the top-level directory of this distribution for the individual copyright * |
||||
|
* holder information and the developer policies on copyright and licensing. * |
||||
|
* * |
||||
|
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
||||
|
* SuperNET software, including this file may be copied, modified, propagated * |
||||
|
* or distributed except according to the terms contained in the LICENSE file * |
||||
|
* * |
||||
|
* Removal or modification of this copyright notice is prohibited. * |
||||
|
* * |
||||
|
******************************************************************************/ |
||||
|
#ifdef notyet |
||||
|
|
||||
|
#ifdef DEFINES_ONLY |
||||
|
#ifndef crypto777_console777_h |
||||
|
#define crypto777_console777_h |
||||
|
#include <stdio.h> |
||||
|
#include <stdio.h> |
||||
|
#include <ctype.h> |
||||
|
#include <stdint.h> |
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include "../includes/cJSON.h" |
||||
|
#include "../KV/kv777.c" |
||||
|
#include "../common/system777.c" |
||||
|
|
||||
|
#endif |
||||
|
#else |
||||
|
#ifndef crypto777_console777_c |
||||
|
#define crypto777_console777_c |
||||
|
|
||||
|
#ifndef crypto777_console777_h |
||||
|
#define DEFINES_ONLY |
||||
|
#include "console777.c" |
||||
|
#undef DEFINES_ONLY |
||||
|
#endif |
||||
|
|
||||
|
int32_t getline777(char *line,int32_t max) |
||||
|
{ |
||||
|
#ifndef _WIN32 |
||||
|
static char prevline[1024]; |
||||
|
struct timeval timeout; |
||||
|
fd_set fdset; |
||||
|
int32_t s; |
||||
|
line[0] = 0; |
||||
|
FD_ZERO(&fdset); |
||||
|
FD_SET(STDIN_FILENO,&fdset); |
||||
|
timeout.tv_sec = 0, timeout.tv_usec = 10000; |
||||
|
if ( (s= select(1,&fdset,NULL,NULL,&timeout)) < 0 ) |
||||
|
fprintf(stderr,"wait_for_input: error select s.%d\n",s); |
||||
|
else |
||||
|
{ |
||||
|
if ( FD_ISSET(STDIN_FILENO,&fdset) > 0 && fgets(line,max,stdin) == line ) |
||||
|
{ |
||||
|
line[strlen(line)-1] = 0; |
||||
|
if ( line[0] == 0 || (line[0] == '.' && line[1] == 0) ) |
||||
|
strcpy(line,prevline); |
||||
|
else strcpy(prevline,line); |
||||
|
} |
||||
|
} |
||||
|
return((int32_t)strlen(line)); |
||||
|
#else |
||||
|
fgets(line, max, stdin); |
||||
|
line[strlen(line)-1] = 0; |
||||
|
return((int32_t)strlen(line)); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
int32_t settoken(char *token,char *line) |
||||
|
{ |
||||
|
int32_t i; |
||||
|
for (i=0; i<32&&line[i]!=0; i++) |
||||
|
{ |
||||
|
if ( line[i] == ' ' || line[i] == '\n' || line[i] == '\t' || line[i] == '\b' || line[i] == '\r' ) |
||||
|
break; |
||||
|
token[i] = line[i]; |
||||
|
} |
||||
|
token[i] = 0; |
||||
|
return(i); |
||||
|
} |
||||
|
|
||||
|
void update_alias(char *line) |
||||
|
{ |
||||
|
char retbuf[8192],alias[1024],*value; int32_t i,err; |
||||
|
if ( (i= settoken(&alias[1],line)) < 0 ) |
||||
|
return; |
||||
|
if ( line[i] == 0 ) |
||||
|
value = &line[i]; |
||||
|
else value = &line[i+1]; |
||||
|
line[i] = 0; |
||||
|
alias[0] = '#'; |
||||
|
printf("i.%d alias.(%s) value.(%s)\n",i,alias,value); |
||||
|
if ( value[0] == 0 ) |
||||
|
printf("warning value for %s is null\n",alias); |
||||
|
kv777_findstr(retbuf,sizeof(retbuf),SUPERNET.alias,alias); |
||||
|
if ( strcmp(retbuf,value) == 0 ) |
||||
|
printf("UNCHANGED "); |
||||
|
else printf("%s ",retbuf[0] == 0 ? "CREATE" : "UPDATE"); |
||||
|
printf(" (%s) -> (%s)\n",alias,value); |
||||
|
if ( (err= kv777_addstr(SUPERNET.alias,alias,value)) != 0 ) |
||||
|
printf("error.%d updating alias database\n",err); |
||||
|
} |
||||
|
|
||||
|
char *expand_aliases(char *_expanded,char *_expanded2,int32_t max,char *line) |
||||
|
{ |
||||
|
char alias[64],value[8192],*expanded,*otherbuf; |
||||
|
int32_t i,j,k,len=0,flag = 1; |
||||
|
expanded = _expanded, otherbuf = _expanded2; |
||||
|
while ( len < max-8192 && flag != 0 ) |
||||
|
{ |
||||
|
flag = 0; |
||||
|
len = (int32_t)strlen(line); |
||||
|
for (i=j=0; i<len; i++) |
||||
|
{ |
||||
|
if ( line[i] == '#' ) |
||||
|
{ |
||||
|
if ( (k= settoken(&alias[1],&line[i+1])) <= 0 ) |
||||
|
continue; |
||||
|
i += k; |
||||
|
alias[0] = '#'; |
||||
|
if ( kv777_findstr(value,sizeof(value),SUPERNET.alias,alias) != 0 ) |
||||
|
{ |
||||
|
if ( value[0] != 0 ) |
||||
|
for (k=0; value[k]!=0; k++) |
||||
|
expanded[j++] = value[k]; |
||||
|
expanded[j] = 0; |
||||
|
//printf("found (%s) -> (%s) [%s]\n",alias,value,expanded);
|
||||
|
flag++; |
||||
|
} |
||||
|
} else expanded[j++] = line[i]; |
||||
|
} |
||||
|
expanded[j] = 0; |
||||
|
line = expanded; |
||||
|
if ( expanded == _expanded2 ) |
||||
|
expanded = _expanded, otherbuf = _expanded2; |
||||
|
else expanded = _expanded2, otherbuf = _expanded; |
||||
|
} |
||||
|
//printf("(%s) -> (%s) len.%d flag.%d\n",line,expanded,len,flag);
|
||||
|
return(line); |
||||
|
} |
||||
|
|
||||
|
char *localcommand(char *line) |
||||
|
{ |
||||
|
char *retstr; |
||||
|
if ( strcmp(line,"list") == 0 ) |
||||
|
{ |
||||
|
if ( (retstr= relays_jsonstr(0,0)) != 0 ) |
||||
|
{ |
||||
|
printf("%s\n",retstr); |
||||
|
free(retstr); |
||||
|
} |
||||
|
return(0); |
||||
|
} |
||||
|
else if ( strncmp(line,"alias",5) == 0 ) |
||||
|
{ |
||||
|
update_alias(line+6); |
||||
|
return(0); |
||||
|
} |
||||
|
else if ( strcmp(line,"help") == 0 ) |
||||
|
{ |
||||
|
printf("local commands:\nhelp, list, alias <name> <any string> then #name is expanded to <any string>\n"); |
||||
|
printf("alias expansions are iterated, so be careful with recursive macros!\n\n"); |
||||
|
|
||||
|
printf("<plugin name> <method> {json args} -> invokes plugin with method and args, \"myipaddr\" and \"NXT\" are default attached\n\n"); |
||||
|
printf("network commands: default timeout is used if not specified\n"); |
||||
|
printf("relay <plugin name> <method> {json args} -> will send to random relay\n"); |
||||
|
printf("peers <plugin name> <method> {json args} -> will send all peers\n"); |
||||
|
printf("!<plugin name> <method> {json args} -> sends to random relay which will send to all its peers and combine results.\n\n"); |
||||
|
|
||||
|
printf("publish shortcut: pub <any string> -> invokes the subscriptions plugin with publish method and all subscribers will be sent <any string>\n\n"); |
||||
|
|
||||
|
printf("direct to specific relay needs to have a direct connection established first:\nrelay direct or peers direct <ipaddr>\n"); |
||||
|
printf("in case you cant directly reach a specific relay with \"peers direct <ipaddr>\" you can add \"!\" and let a relay broadcast\n"); |
||||
|
printf("without an <ipaddr> it will connect to a random relay. Once directly connected, commands are sent by:\n"); |
||||
|
printf("<ipaddress> {\"plugin\":\"<name>\",\"method\":\"<methodname>\",...}\n"); |
||||
|
printf("responses to direct requests are sent through as a subscription feed\n\n"); |
||||
|
|
||||
|
printf("\"relay join\" adds your node to the list of relay nodes, your node will need to stay in sync with the other relays\n"); |
||||
|
//printf("\"relay mailbox <64bit number> <name>\" creates synchronized storage in all relays\n");
|
||||
|
return(0); |
||||
|
} |
||||
|
return(line); |
||||
|
} |
||||
|
|
||||
|
char *parse_expandedline(char *plugin,int32_t max,char *method,int32_t *timeoutp,char *line,int32_t broadcastflag) |
||||
|
{ |
||||
|
int32_t i,j; char numstr[64],*pubstr,*cmdstr = 0; cJSON *json; uint64_t tag; struct destbuf tmp; |
||||
|
for (i=0; i<512&&line[i]!=' '&&line[i]!=0; i++) |
||||
|
plugin[i] = line[i]; |
||||
|
plugin[i] = 0; |
||||
|
*timeoutp = 0; |
||||
|
pubstr = line; |
||||
|
if ( strcmp(plugin,"pub") == 0 ) |
||||
|
strcpy(plugin,"subscriptions"), strcpy(method,"publish"), pubstr += 4; |
||||
|
else if ( line[i+1] != 0 ) |
||||
|
{ |
||||
|
for (++i,j=0; i<512&&line[i]!=' '&&line[i]!=0; i++,j++) |
||||
|
method[j] = line[i]; |
||||
|
method[j] = 0; |
||||
|
} else method[0] = 0; |
||||
|
if ( (json= cJSON_Parse(line+i+1)) == 0 ) |
||||
|
json = cJSON_CreateObject(); |
||||
|
if ( json != 0 ) |
||||
|
{ |
||||
|
if ( strcmp("direct",method) == 0 && cJSON_GetObjectItem(json,"myipaddr") == 0 ) |
||||
|
cJSON_AddItemToObject(json,"myipaddr",cJSON_CreateString(SUPERNET.myipaddr)); |
||||
|
if ( cJSON_GetObjectItem(json,"tag") == 0 ) |
||||
|
randombytes((void *)&tag,sizeof(tag)), sprintf(numstr,"%llu",(long long)tag), cJSON_AddItemToObject(json,"tag",cJSON_CreateString(numstr)); |
||||
|
//if ( cJSON_GetObjectItem(json,"NXT") == 0 )
|
||||
|
// cJSON_AddItemToObject(json,"NXT",cJSON_CreateString(SUPERNET.NXTADDR));
|
||||
|
*timeoutp = juint(json,"timeout"); |
||||
|
if ( plugin[0] == 0 ) |
||||
|
strcpy(plugin,"relay"); |
||||
|
if ( cJSON_GetObjectItem(json,"plugin") == 0 ) |
||||
|
cJSON_AddItemToObject(json,"plugin",cJSON_CreateString(plugin)); |
||||
|
else copy_cJSON(&tmp,cJSON_GetObjectItem(json,"plugin")), safecopy(plugin,tmp.buf,max); |
||||
|
if ( method[0] == 0 ) |
||||
|
strcpy(method,"help"); |
||||
|
cJSON_AddItemToObject(json,"method",cJSON_CreateString(method)); |
||||
|
if ( broadcastflag != 0 ) |
||||
|
cJSON_AddItemToObject(json,"broadcast",cJSON_CreateString("allrelays")); |
||||
|
cmdstr = cJSON_Print(json), _stripwhite(cmdstr,' '); |
||||
|
return(cmdstr); |
||||
|
} |
||||
|
else return(clonestr(pubstr)); |
||||
|
} |
||||
|
|
||||
|
char *process_user_json(char *plugin,char *method,char *cmdstr,int32_t broadcastflag,int32_t timeout) |
||||
|
{ |
||||
|
struct daemon_info *find_daemoninfo(int32_t *indp,char *name,uint64_t daemonid,uint64_t instanceid); |
||||
|
uint32_t nonce; int32_t tmp,len; char *retstr;//,tokenized[8192];
|
||||
|
len = (int32_t)strlen(cmdstr) + 1; |
||||
|
//printf("userjson.(%s).%d plugin.(%s) broadcastflag.%d method.(%s)\n",cmdstr,len,plugin,broadcastflag,method);
|
||||
|
if ( broadcastflag != 0 || strcmp(plugin,"relay") == 0 ) |
||||
|
{ |
||||
|
if ( strcmp(method,"busdata") == 0 ) |
||||
|
retstr = busdata_sync(&nonce,cmdstr,broadcastflag==0?0:"allnodes",0); |
||||
|
else retstr = clonestr("{\"error\":\"direct load balanced calls deprecated, use busdata\"}"); |
||||
|
} |
||||
|
//else if ( strcmp(plugin,"peers") == 0 )
|
||||
|
// retstr = nn_allrelays((uint8_t *)cmdstr,len,timeout,0);
|
||||
|
else if ( find_daemoninfo(&tmp,plugin,0,0) != 0 ) |
||||
|
{ |
||||
|
//len = construct_tokenized_req(tokenized,cmdstr,SUPERNET.NXTACCTSECRET,broadcastflag!=0?"allnodes":0);
|
||||
|
//printf("console.(%s)\n",tokenized);
|
||||
|
retstr = plugin_method(-1,0,1,plugin,method,0,0,cmdstr,len,timeout != 0 ? timeout : 0,0); |
||||
|
} |
||||
|
else retstr = clonestr("{\"error\":\"invalid command\"}"); |
||||
|
return(retstr); |
||||
|
} |
||||
|
|
||||
|
// ./BitcoinDarkd SuperNET '{"plugin":"ramchain","method":"create","coin":"BTC"}'
|
||||
|
|
||||
|
void process_userinput(char *_line) |
||||
|
{ |
||||
|
static char *line,*line2,*match = "./BitcoinDarkd SuperNET '"; |
||||
|
char plugin[512],ipaddr[1024],method[512],*cmdstr,*retstr; cJSON *json; int i,j,len,timeout,broadcastflag = 0; |
||||
|
len = (int32_t)strlen(match); |
||||
|
if ( _line[strlen(_line)-1] == '\'' && strncmp(_line,match,len) == 0 ) |
||||
|
{ |
||||
|
_line[strlen(_line)-1] = 0; |
||||
|
_line += len; |
||||
|
} |
||||
|
printf("%02x %02x %02x %02x %02x\n",0xff & _line[0],0xff & _line[1],0xff & _line[2],0xff & _line[3],0xff & _line[4]); |
||||
|
for (i=j=0; _line[i]!=0; i++) |
||||
|
{ |
||||
|
if ( (uint8_t)_line[i] == 0xe2 && (uint8_t)_line[i+1] == 0x80 ) |
||||
|
{ |
||||
|
if ( (uint8_t)_line[i+2] == 0x99 ) |
||||
|
_line[j++] = '\'', i += 2; |
||||
|
else if ( (uint8_t)_line[i+2] == 0x9c || (uint8_t)_line[i+2] == 0x9d ) |
||||
|
_line[j++] = '"', i += 2; |
||||
|
else _line[j++] = _line[i]; |
||||
|
} |
||||
|
else _line[j++] = _line[i]; |
||||
|
//else if ( (uint8_t)_line[i] == 0x9c )
|
||||
|
// _line[i] = '"';
|
||||
|
} |
||||
|
_line[j++] = 0; |
||||
|
if ( (json= cJSON_Parse(_line)) != 0 ) |
||||
|
{ |
||||
|
char *process_nn_message(int32_t sock,char *jsonstr); |
||||
|
free_json(json); |
||||
|
retstr = SuperNET_JSON(_line); |
||||
|
//retstr = process_nn_message(-1,line);
|
||||
|
//retstr = nn_loadbalanced((uint8_t *)line,(int32_t)strlen(line)+1);
|
||||
|
fprintf(stderr,"console.(%s) -> (%s)\n",_line,retstr); |
||||
|
return; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
for (i=0; _line[i]!=0; i++) |
||||
|
printf("(%c %02x) ",_line[i],_line[i]&0xff); |
||||
|
printf("cant parse.(%s)\n",line); |
||||
|
} |
||||
|
printf("[%s]\n",_line); |
||||
|
if ( line == 0 ) |
||||
|
line = calloc(1,65536), line2 = calloc(1,65536); |
||||
|
expand_aliases(line,line2,65536,_line); |
||||
|
if ( (line= localcommand(line)) == 0 ) |
||||
|
return; |
||||
|
if ( line[0] == '!' ) |
||||
|
broadcastflag = 1, line++; |
||||
|
settoken(ipaddr,line); |
||||
|
printf("expands to: %s [%s] %s\n",broadcastflag != 0 ? "broadcast": "",line,ipaddr); |
||||
|
if ( is_ipaddr(ipaddr) != 0 ) |
||||
|
{ |
||||
|
line += strlen(ipaddr) + 1; |
||||
|
if ( (cmdstr = parse_expandedline(plugin,sizeof(plugin),method,&timeout,line,broadcastflag)) != 0 ) |
||||
|
{ |
||||
|
printf("ipaddr.(%s) (%s)\n",ipaddr,line); |
||||
|
//retstr = nn_direct(ipaddr,(uint8_t *)line,(int32_t)strlen(line)+1);
|
||||
|
printf("deprecated (%s) -> (%s)\n",line,cmdstr); |
||||
|
free(cmdstr); |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
if ( (cmdstr= parse_expandedline(plugin,sizeof(plugin),method,&timeout,line,broadcastflag)) != 0 ) |
||||
|
{ |
||||
|
retstr = process_user_json(plugin,method,cmdstr,broadcastflag,timeout != 0 ? timeout : SUPERNET.PLUGINTIMEOUT); |
||||
|
printf("CONSOLE (%s) -> (%s) -> (%s)\n",line,cmdstr,retstr); |
||||
|
free(cmdstr); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#endif |
File diff suppressed because it is too large
@ -0,0 +1,605 @@ |
|||||
|
<!DOCTYPE HTML> |
||||
|
<html style="overflow-y:scroll;-webkit-user-select: text"> |
||||
|
<head> |
||||
|
<meta http-equiv="Pragma" content="no-cache"> |
||||
|
<meta http-equiv="Expires" content="-1"> |
||||
|
<title>SuperNET</title> |
||||
|
</head> |
||||
|
<body data-custom-load="true" data-name="SuperNET" data-tools="pnacl newlib glibc clang-newlib mac" data-configs="Debug Release" data-path="{tc}/{config}"> |
||||
|
<div class="debuglog" hidden> |
||||
|
<pre id="log" style="font-weight: bold"></pre> |
||||
|
</div> |
||||
|
<div id="listener"></div> |
||||
|
<script type="text/javascript"> |
||||
|
var isTest = false; |
||||
|
var isRelease = true; |
||||
|
// Javascript module pattern: |
||||
|
// see http://en.wikipedia.org/wiki/Unobtrusive_JavaScript#Namespaces |
||||
|
// In essence, we define an anonymous function which is immediately called and |
||||
|
// returns a new object. The new object contains only the exported definitions; |
||||
|
// all other definitions in the anonymous function are inaccessible to external |
||||
|
// code. |
||||
|
var common = (function() { |
||||
|
|
||||
|
function isHostToolchain(tool) { |
||||
|
return tool == 'win' || tool == 'linux' || tool == 'mac'; |
||||
|
} |
||||
|
function mimeTypeForTool(tool) { |
||||
|
// For NaCl modules use application/x-nacl. |
||||
|
var mimetype = 'application/x-nacl'; |
||||
|
if (isHostToolchain(tool)) { |
||||
|
// For non-NaCl PPAPI plugins use the x-ppapi-debug/release |
||||
|
// mime type. |
||||
|
if (isRelease) |
||||
|
mimetype = 'application/x-ppapi-release'; |
||||
|
else |
||||
|
mimetype = 'application/x-ppapi-debug'; |
||||
|
} else if (tool == 'pnacl') { |
||||
|
mimetype = 'application/x-pnacl'; |
||||
|
} |
||||
|
return mimetype; |
||||
|
} |
||||
|
function browserSupportsNaCl(tool) { |
||||
|
// Assume host toolchains always work with the given browser. |
||||
|
// The below mime-type checking might not work with |
||||
|
// --register-pepper-plugins. |
||||
|
if (isHostToolchain(tool)) { |
||||
|
return true; |
||||
|
} |
||||
|
var mimetype = mimeTypeForTool(tool); |
||||
|
return navigator.mimeTypes[mimetype] !== undefined; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Inject a script into the DOM, and call a callback when it is loaded. |
||||
|
* |
||||
|
* @param {string} url The url of the script to load. |
||||
|
* @param {Function} onload The callback to call when the script is loaded. |
||||
|
* @param {Function} onerror The callback to call if the script fails to load. |
||||
|
*/ |
||||
|
function injectScript(url, onload, onerror) { |
||||
|
var scriptEl = document.createElement('script'); |
||||
|
scriptEl.type = 'text/javascript'; |
||||
|
scriptEl.src = url; |
||||
|
scriptEl.onload = onload; |
||||
|
if (onerror) { |
||||
|
scriptEl.addEventListener('error', onerror, false); |
||||
|
} |
||||
|
document.head.appendChild(scriptEl); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Run all tests for this example. |
||||
|
* |
||||
|
* @param {Object} moduleEl The module DOM element. |
||||
|
*/ |
||||
|
function runTests(moduleEl) { |
||||
|
console.log('runTests()'); |
||||
|
common.tester = new Tester(); |
||||
|
|
||||
|
// All NaCl SDK examples are OK if the example exits cleanly; (i.e. the |
||||
|
// NaCl module returns 0 or calls exit(0)). |
||||
|
// |
||||
|
// Without this exception, the browser_tester thinks that the module has crashed. |
||||
|
common.tester.exitCleanlyIsOK(); |
||||
|
|
||||
|
common.tester.addAsyncTest('loaded', function(test) { |
||||
|
test.pass(); |
||||
|
}); |
||||
|
|
||||
|
if (typeof window.addTests !== 'undefined') { |
||||
|
window.addTests(); |
||||
|
} |
||||
|
|
||||
|
common.tester.waitFor(moduleEl); |
||||
|
common.tester.run(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Create the Native Client <embed> element as a child of the DOM element |
||||
|
* named "listener". |
||||
|
* |
||||
|
* @param {string} name The name of the example. |
||||
|
* @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc. |
||||
|
* @param {string} path Directory name where .nmf file can be found. |
||||
|
* @param {number} width The width to create the plugin. |
||||
|
* @param {number} height The height to create the plugin. |
||||
|
* @param {Object} attrs Dictionary of attributes to set on the module. |
||||
|
*/ |
||||
|
function createNaClModule(name, tool, path, width, height, attrs) { |
||||
|
var moduleEl = document.createElement('embed'); |
||||
|
moduleEl.setAttribute('name', 'nacl_module'); |
||||
|
moduleEl.setAttribute('id', 'nacl_module'); |
||||
|
moduleEl.setAttribute('width', width); |
||||
|
moduleEl.setAttribute('height', height); |
||||
|
moduleEl.setAttribute('path', path); |
||||
|
moduleEl.setAttribute('src', path + '/' + name + '.nmf'); |
||||
|
|
||||
|
// Add any optional arguments |
||||
|
if (attrs) { |
||||
|
for (var key in attrs) { |
||||
|
moduleEl.setAttribute(key, attrs[key]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var mimetype = mimeTypeForTool(tool); |
||||
|
moduleEl.setAttribute('type', mimetype); |
||||
|
|
||||
|
// The <EMBED> element is wrapped inside a <DIV>, which has both a 'load' |
||||
|
// and a 'message' event listener attached. This wrapping method is used |
||||
|
// instead of attaching the event listeners directly to the <EMBED> element |
||||
|
// to ensure that the listeners are active before the NaCl module 'load' |
||||
|
// event fires. |
||||
|
var listenerDiv = document.getElementById('listener'); |
||||
|
listenerDiv.appendChild(moduleEl); |
||||
|
|
||||
|
// Request the offsetTop property to force a relayout. As of Apr 10, 2014 |
||||
|
// this is needed if the module is being loaded on a Chrome App's |
||||
|
// background page (see crbug.com/350445). |
||||
|
moduleEl.offsetTop; |
||||
|
|
||||
|
// Host plugins don't send a moduleDidLoad message. We'll fake it here. |
||||
|
var isHost = isHostToolchain(tool); |
||||
|
if (isHost) { |
||||
|
window.setTimeout(function() { |
||||
|
moduleEl.readyState = 1; |
||||
|
moduleEl.dispatchEvent(new CustomEvent('loadstart')); |
||||
|
moduleEl.readyState = 4; |
||||
|
moduleEl.dispatchEvent(new CustomEvent('load')); |
||||
|
moduleEl.dispatchEvent(new CustomEvent('loadend')); |
||||
|
}, 100); // 100 ms |
||||
|
} |
||||
|
|
||||
|
// This is code that is only used to test the SDK. |
||||
|
if (isTest) { |
||||
|
var loadNaClTest = function() { |
||||
|
injectScript('nacltest.js', function() { |
||||
|
runTests(moduleEl); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// Try to load test.js for the example. Whether or not it exists, load |
||||
|
// nacltest.js. |
||||
|
injectScript('test.js', loadNaClTest, loadNaClTest); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Add the default "load" and "message" event listeners to the element with |
||||
|
* id "listener". |
||||
|
* |
||||
|
* The "load" event is sent when the module is successfully loaded. The |
||||
|
* "message" event is sent when the naclModule posts a message using |
||||
|
* PPB_Messaging.PostMessage() (in C) or pp::Instance().PostMessage() (in |
||||
|
* C++). |
||||
|
*/ |
||||
|
function attachDefaultListeners() { |
||||
|
var listenerDiv = document.getElementById('listener'); |
||||
|
listenerDiv.addEventListener('load', moduleDidLoad, true); |
||||
|
listenerDiv.addEventListener('message', handleMessage, true); |
||||
|
listenerDiv.addEventListener('error', handleError, true); |
||||
|
listenerDiv.addEventListener('crash', handleCrash, true); |
||||
|
if (typeof window.attachListeners !== 'undefined') { |
||||
|
window.attachListeners(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Called when the NaCl module fails to load. |
||||
|
* |
||||
|
* This event listener is registered in createNaClModule above. |
||||
|
*/ |
||||
|
function handleError(event) { |
||||
|
// We can't use common.naclModule yet because the module has not been |
||||
|
// loaded. |
||||
|
var moduleEl = document.getElementById('nacl_module'); |
||||
|
updateStatus('ERROR [' + moduleEl.lastError + ']'); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Called when the Browser can not communicate with the Module |
||||
|
* |
||||
|
* This event listener is registered in attachDefaultListeners above. |
||||
|
*/ |
||||
|
function handleCrash(event) { |
||||
|
if (common.naclModule.exitStatus != 0) { |
||||
|
updateStatus('ABORTED [' + common.naclModule.exitStatus + ']'); |
||||
|
} else { |
||||
|
updateStatus('EXITED [' + common.naclModule.exitStatus + ']'); |
||||
|
} |
||||
|
if (typeof window.handleCrash !== 'undefined') { |
||||
|
window.handleCrash(common.naclModule.lastError); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Called when the NaCl module is loaded. |
||||
|
* |
||||
|
* This event listener is registered in attachDefaultListeners above. |
||||
|
*/ |
||||
|
function moduleDidLoad() { |
||||
|
common.naclModule = document.getElementById('nacl_module'); |
||||
|
updateStatus('RUNNING'); |
||||
|
|
||||
|
if (typeof window.moduleDidLoad !== 'undefined') { |
||||
|
window.moduleDidLoad(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Hide the NaCl module's embed element. |
||||
|
* |
||||
|
* We don't want to hide by default; if we do, it is harder to determine that |
||||
|
* a plugin failed to load. Instead, call this function inside the example's |
||||
|
* "moduleDidLoad" function. |
||||
|
* |
||||
|
*/ |
||||
|
function hideModule() { |
||||
|
// Setting common.naclModule.style.display = "None" doesn't work; the |
||||
|
// module will no longer be able to receive postMessages. |
||||
|
common.naclModule.style.height = '0'; |
||||
|
} |
||||
|
function removeModule() { |
||||
|
common.naclModule.parentNode.removeChild(common.naclModule); |
||||
|
common.naclModule = null; |
||||
|
} |
||||
|
function startsWith(s, prefix) { |
||||
|
// indexOf would search the entire string, lastIndexOf(p, 0) only checks at |
||||
|
// the first index. See: http://stackoverflow.com/a/4579228 |
||||
|
return s.lastIndexOf(prefix, 0) === 0; |
||||
|
} |
||||
|
var kMaxLogMessageLength = 777; |
||||
|
var logMessageArray = []; |
||||
|
function logMessage(message) { |
||||
|
logMessageArray.push(message); |
||||
|
if ( logMessageArray.length > kMaxLogMessageLength ) |
||||
|
logMessageArray.shift(); |
||||
|
|
||||
|
var node = document.createElement("div"); // Create a node |
||||
|
var textnode = document.createTextNode(message); // Create a text node |
||||
|
node.appendChild(textnode); // Append the text to <li> |
||||
|
document.getElementById("log").appendChild(node); |
||||
|
|
||||
|
//document.getElementById('log').appendChild(message); |
||||
|
console.log(message); |
||||
|
} |
||||
|
var defaultMessageTypes = { |
||||
|
'alert': alert, |
||||
|
'log': logMessage |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Called when the NaCl module sends a message to JavaScript (via |
||||
|
* PPB_Messaging.PostMessage()) |
||||
|
* |
||||
|
* This event listener is registered in createNaClModule above. |
||||
|
* |
||||
|
* @param {Event} message_event A message event. message_event.data contains |
||||
|
* the data sent from the NaCl module. |
||||
|
*/ |
||||
|
|
||||
|
function retmsg(msg) |
||||
|
{ |
||||
|
common.naclModule.postMessage(msg); |
||||
|
console.log("sent: "+msg); |
||||
|
} |
||||
|
|
||||
|
function handleMessage(message_event) |
||||
|
{ |
||||
|
if (typeof message_event.data === 'string') { |
||||
|
for (var type in defaultMessageTypes) { |
||||
|
if (defaultMessageTypes.hasOwnProperty(type)) { |
||||
|
if (startsWith(message_event.data, type + ':')) { |
||||
|
func = defaultMessageTypes[type]; |
||||
|
func(message_event.data.slice(type.length + 1)); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (typeof window.handleMessage !== 'undefined') { |
||||
|
window.handleMessage(message_event); |
||||
|
return; |
||||
|
} |
||||
|
logMessage('Unhandled message: ' + message_event.data); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Called when the DOM content has loaded; i.e. the page's document is fully |
||||
|
* parsed. At this point, we can safely query any elements in the document via |
||||
|
* document.querySelector, document.getElementById, etc. |
||||
|
* |
||||
|
* @param {string} name The name of the example. |
||||
|
* @param {string} tool The name of the toolchain, e.g. "glibc", "newlib" etc. |
||||
|
* @param {string} path Directory name where .nmf file can be found. |
||||
|
* @param {number} width The width to create the plugin. |
||||
|
* @param {number} height The height to create the plugin. |
||||
|
* @param {Object} attrs Optional dictionary of additional attributes. |
||||
|
*/ |
||||
|
function domContentLoaded(name, tool, path, width, height, attrs) { |
||||
|
// If the page loads before the Native Client module loads, then set the |
||||
|
// status message indicating that the module is still loading. Otherwise, |
||||
|
// do not change the status message. |
||||
|
updateStatus('Page loaded.'); |
||||
|
if (!browserSupportsNaCl(tool)) { |
||||
|
updateStatus( |
||||
|
'Browser does not support NaCl (' + tool + '), or NaCl is disabled'); |
||||
|
} else if (common.naclModule == null) { |
||||
|
updateStatus('Creating embed: ' + tool); |
||||
|
|
||||
|
// We use a non-zero sized embed to give Chrome space to place the bad |
||||
|
// plug-in graphic, if there is a problem. |
||||
|
width = typeof width !== 'undefined' ? width : 200; |
||||
|
height = typeof height !== 'undefined' ? height : 200; |
||||
|
attachDefaultListeners(); |
||||
|
createNaClModule(name, tool, path, width, height, attrs); |
||||
|
} else { |
||||
|
// It's possible that the Native Client module onload event fired |
||||
|
// before the page's onload event. In this case, the status message |
||||
|
// will reflect 'SUCCESS', but won't be displayed. This call will |
||||
|
// display the current message. |
||||
|
updateStatus('Waiting.'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** Saved text to display in the element with id 'statusField'. */ |
||||
|
var statusText = 'NO-STATUSES'; |
||||
|
|
||||
|
/** |
||||
|
* Set the global status message. If the element with id 'statusField' |
||||
|
* exists, then set its HTML to the status message as well. |
||||
|
* |
||||
|
* @param {string} opt_message The message to set. If null or undefined, then |
||||
|
* set element 'statusField' to the message from the last call to |
||||
|
* updateStatus. |
||||
|
*/ |
||||
|
function updateStatus(opt_message) { |
||||
|
if (opt_message) { |
||||
|
statusText = opt_message; |
||||
|
} |
||||
|
var statusField = document.getElementById('statusField'); |
||||
|
if (statusField) { |
||||
|
statusField.innerHTML = statusText; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// The symbols to export. |
||||
|
return { |
||||
|
/** A reference to the NaCl module, once it is loaded. */ |
||||
|
naclModule: null, |
||||
|
|
||||
|
attachDefaultListeners: attachDefaultListeners, |
||||
|
domContentLoaded: domContentLoaded, |
||||
|
createNaClModule: createNaClModule, |
||||
|
hideModule: hideModule, |
||||
|
removeModule: removeModule, |
||||
|
logMessage: logMessage, |
||||
|
updateStatus: updateStatus |
||||
|
}; |
||||
|
|
||||
|
}()); |
||||
|
|
||||
|
// Listen for the DOM content to be loaded. This event is fired when parsing of |
||||
|
// the page's document has finished. |
||||
|
document.addEventListener('DOMContentLoaded', function() { |
||||
|
|
||||
|
var body = document.body; |
||||
|
|
||||
|
// The data-* attributes on the body can be referenced via body.dataset. |
||||
|
if (body.dataset) { |
||||
|
var loadFunction; |
||||
|
if (!body.dataset.customLoad) { |
||||
|
loadFunction = common.domContentLoaded; |
||||
|
} else if (typeof window.domContentLoaded !== 'undefined') { |
||||
|
loadFunction = window.domContentLoaded; |
||||
|
} |
||||
|
|
||||
|
// From https://developer.mozilla.org/en-US/docs/DOM/window.location |
||||
|
var searchVars = {}; |
||||
|
if (window.location.search.length > 1) { |
||||
|
var pairs = window.location.search.substr(1).split('&'); |
||||
|
for (var key_ix = 0; key_ix < pairs.length; key_ix++) { |
||||
|
var keyValue = pairs[key_ix].split('='); |
||||
|
searchVars[unescape(keyValue[0])] = |
||||
|
keyValue.length > 1 ? unescape(keyValue[1]) : ''; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (loadFunction) { |
||||
|
var toolchains = body.dataset.tools.split(' '); |
||||
|
var configs = body.dataset.configs.split(' '); |
||||
|
|
||||
|
var attrs = {}; |
||||
|
if (body.dataset.attrs) { |
||||
|
var attr_list = body.dataset.attrs.split(' '); |
||||
|
for (var key in attr_list) { |
||||
|
var attr = attr_list[key].split('='); |
||||
|
var key = attr[0]; |
||||
|
var value = attr[1]; |
||||
|
attrs[key] = value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var tc = toolchains.indexOf(searchVars.tc) !== -1 ? |
||||
|
searchVars.tc : toolchains[0]; |
||||
|
|
||||
|
// If the config value is included in the search vars, use that. |
||||
|
// Otherwise default to Release if it is valid, or the first value if |
||||
|
// Release is not valid. |
||||
|
if (configs.indexOf(searchVars.config) !== -1) |
||||
|
var config = searchVars.config; |
||||
|
else if (configs.indexOf('Release') !== -1) |
||||
|
var config = 'Release'; |
||||
|
else |
||||
|
var config = configs[0]; |
||||
|
|
||||
|
var pathFormat = body.dataset.path; |
||||
|
var path = pathFormat.replace('{tc}', tc).replace('{config}', config); |
||||
|
|
||||
|
isTest = searchVars.test === 'true'; |
||||
|
isRelease = path.toLowerCase().indexOf('release') != -1; |
||||
|
|
||||
|
loadFunction(body.dataset.name, tc, path, body.dataset.width, |
||||
|
body.dataset.height, attrs); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
</script> |
||||
|
<script type="text/javascript"> |
||||
|
function moduleDidLoad() { |
||||
|
common.hideModule(); |
||||
|
} |
||||
|
|
||||
|
function $(id) { |
||||
|
return document.getElementById(id); |
||||
|
} |
||||
|
|
||||
|
// Called by the common.js module. |
||||
|
function domContentLoaded(name, tc, config, width, height) { |
||||
|
navigator.webkitPersistentStorage.requestQuota(10000000000, |
||||
|
function(bytes) { |
||||
|
common.updateStatus( |
||||
|
'Allocated ' + bytes + ' bytes of persistent storage. Running the first time will take 17 seconds to load'); |
||||
|
common.attachDefaultListeners(); |
||||
|
common.createNaClModule(name, tc, config, width, height); |
||||
|
}, |
||||
|
function(e) { alert('Failed to allocate space') }); |
||||
|
} |
||||
|
|
||||
|
// Called by the common.js module. |
||||
|
function attachListeners() { |
||||
|
var radioEls = document.querySelectorAll('input[type="radio"]'); |
||||
|
for (var i = 0; i < radioEls.length; ++i) { |
||||
|
radioEls[i].addEventListener('click', onRadioClicked); |
||||
|
} |
||||
|
|
||||
|
// Wire up the 'click' event for each function's button. |
||||
|
var functionEls = document.querySelectorAll('.function'); |
||||
|
for (var i = 0; i < functionEls.length; ++i) { |
||||
|
var functionEl = functionEls[i]; |
||||
|
var id = functionEl.getAttribute('id'); |
||||
|
var buttonEl = functionEl.querySelector('button'); |
||||
|
|
||||
|
// The function name matches the element id. |
||||
|
var func = window[id]; |
||||
|
buttonEl.addEventListener('click', func); |
||||
|
} |
||||
|
//$('pipe_input_box').addEventListener('keypress', onPipeInput) |
||||
|
//$('pipe_output').disabled = true; |
||||
|
//$('pipe_name').addEventListener('change', function() { $('pipe_output').value = ''; }) |
||||
|
} |
||||
|
|
||||
|
// Called with keypress events on the pipe input box |
||||
|
function onPipeInput(e) { |
||||
|
// Create an arraybuffer containing the 16-bit char code |
||||
|
// from the keypress event. |
||||
|
var buffer = new ArrayBuffer(1*2); |
||||
|
var bufferView = new Uint16Array(buffer); |
||||
|
bufferView[0] = e.charCode; |
||||
|
|
||||
|
// Pass the buffer in a dictionary over the NaCl module |
||||
|
var pipeSelect = $('pipe_name'); |
||||
|
var pipeName = pipeSelect[pipeSelect.selectedIndex].value; |
||||
|
var message = { |
||||
|
pipe: pipeName, |
||||
|
operation: 'write', |
||||
|
payload: buffer, |
||||
|
}; |
||||
|
nacl_module.postMessage(message); |
||||
|
e.preventDefault(); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
function onRadioClicked(e) { |
||||
|
var divId = this.id.slice(5); // skip "radio" |
||||
|
var functionEls = document.querySelectorAll('.function'); |
||||
|
for (var i = 0; i < functionEls.length; ++i) { |
||||
|
var visible = functionEls[i].id === divId; |
||||
|
if (functionEls[i].id === divId) |
||||
|
functionEls[i].removeAttribute('hidden'); |
||||
|
else |
||||
|
functionEls[i].setAttribute('hidden', ''); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function addNameToSelectElements(cssClass, handle, name) { |
||||
|
var text = '[' + handle + '] ' + name; |
||||
|
var selectEls = document.querySelectorAll(cssClass); |
||||
|
for (var i = 0; i < selectEls.length; ++i) { |
||||
|
var optionEl = document.createElement('option'); |
||||
|
optionEl.setAttribute('value', handle); |
||||
|
optionEl.appendChild(document.createTextNode(text)); |
||||
|
selectEls[i].appendChild(optionEl); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function removeNameFromSelectElements(cssClass, handle) { |
||||
|
var optionEls = document.querySelectorAll(cssClass + ' > option'); |
||||
|
for (var i = 0; i < optionEls.length; ++i) { |
||||
|
var optionEl = optionEls[i]; |
||||
|
if (optionEl.value == handle) { |
||||
|
var selectEl = optionEl.parentNode; |
||||
|
selectEl.removeChild(optionEl); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var funcToCallback = {}; |
||||
|
|
||||
|
function postCall(func) { |
||||
|
var callback = arguments[arguments.length - 1]; |
||||
|
funcToCallback[func] = callback; |
||||
|
|
||||
|
nacl_module.postMessage({ |
||||
|
cmd: func, |
||||
|
args: Array.prototype.slice.call(arguments, 1, -1) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function ArrayBufferToString(buf) { return String.fromCharCode.apply(null, new Uint16Array(buf)); } |
||||
|
|
||||
|
// Called by the common.js module. |
||||
|
function handleMessage(message_event) { |
||||
|
var data = message_event.data; |
||||
|
if ((typeof(data) === 'string' || data instanceof String)) { |
||||
|
common.logMessage(data); |
||||
|
} |
||||
|
else if (data instanceof Object) |
||||
|
{ |
||||
|
var pipeName = data['pipe'] |
||||
|
if ( pipeName !== undefined ) |
||||
|
{ |
||||
|
// Message for JavaScript I/O pipe |
||||
|
var operation = data['operation']; |
||||
|
if (operation == 'write') { |
||||
|
$('pipe_output').value += ArrayBufferToString(data['payload']); |
||||
|
} else if (operation == 'ack') { |
||||
|
common.logMessage(pipeName + ": ack:" + data['payload']); |
||||
|
} else { |
||||
|
common.logMessage('Got unexpected pipe operation: ' + operation); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// Result from a function call. |
||||
|
var params = data.args; |
||||
|
var funcName = data.cmd; |
||||
|
var callback = funcToCallback[funcName]; |
||||
|
if (!callback) |
||||
|
{ |
||||
|
common.logMessage('Error: Bad message ' + funcName + ' received from NaCl module.'); |
||||
|
return; |
||||
|
} |
||||
|
delete funcToCallback[funcName]; |
||||
|
callback.apply(null, params); |
||||
|
} |
||||
|
} else { |
||||
|
common.logMessage('Error: Unknow message `' + data + '` received from NaCl module.'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,254 @@ |
|||||
|
/******************************************************************************
|
||||
|
* Copyright © 2014-2015 The SuperNET Developers. * |
||||
|
* * |
||||
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
||||
|
* the top-level directory of this distribution for the individual copyright * |
||||
|
* holder information and the developer policies on copyright and licensing. * |
||||
|
* * |
||||
|
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
||||
|
* SuperNET software, including this file may be copied, modified, propagated * |
||||
|
* or distributed except according to the terms contained in the LICENSE file * |
||||
|
* * |
||||
|
* Removal or modification of this copyright notice is prohibited. * |
||||
|
* * |
||||
|
******************************************************************************/ |
||||
|
#ifdef notyet |
||||
|
|
||||
|
#include "SuperNET.h" |
||||
|
|
||||
|
#define BUNDLED |
||||
|
#define PLUGINSTR "relay" |
||||
|
#define PLUGNAME(NAME) relay ## NAME |
||||
|
#define STRUCTNAME struct PLUGNAME(_info) |
||||
|
#define STRINGIFY(NAME) #NAME |
||||
|
#define PLUGIN_EXTRASIZE sizeof(STRUCTNAME) |
||||
|
|
||||
|
|
||||
|
#define NN_WS -4 |
||||
|
|
||||
|
char *PLUGNAME(_methods)[] = { "list", "add", "direct", "join", "busdata", "msigaddr", "allservices", "telepathy" }; // list of supported methods
|
||||
|
|
||||
|
int32_t nn_typelist[] = { NN_REP, NN_REQ, NN_RESPONDENT, NN_SURVEYOR, NN_PUB, NN_SUB, NN_PULL, NN_PUSH, NN_BUS, NN_PAIR }; |
||||
|
char *nn_transports[] = { "tcp", "ws", "ipc", "inproc", "tcpmux", "tbd1", "tbd2", "tbd3" }; |
||||
|
|
||||
|
void calc_nonces(char *destpoint) |
||||
|
{ |
||||
|
char buf[8192],*str; int32_t n = 0; double endmilli = milliseconds() + 60000; |
||||
|
//printf("calc_nonces.(%s)\n",destpoint);
|
||||
|
memset(SUPERNET.nonces,0,sizeof(SUPERNET.nonces)); |
||||
|
SUPERNET.numnonces = 0; |
||||
|
while ( milliseconds() < endmilli && n < sizeof(SUPERNET.nonces)/sizeof(*SUPERNET.nonces) ) |
||||
|
{ |
||||
|
sprintf(buf,"{\"plugin\":\"relay\",\"counter\":\"%d\",\"destplugin\":\"relay\",\"method\":\"nonce\",\"broadcast\":\"8\",\"lbendpoint\":\"%s\",\"relaypoint\":\"%s\",\"globalpoint\":\"%s\",\"destpoint\":\"%s\",\"NXT\":\"%s\"}",n,SUPERNET.lbendpoint,SUPERNET.relayendpoint,SUPERNET.globalendpoint,destpoint,SUPERNET.NXTADDR); |
||||
|
if ( (str= busdata_sync(&SUPERNET.nonces[n],buf,"8",0)) != 0 ) |
||||
|
{ |
||||
|
//fprintf(stderr,"send.(%s)\n",buf);
|
||||
|
free(str); |
||||
|
n++; |
||||
|
} |
||||
|
} |
||||
|
SUPERNET.numnonces = n; |
||||
|
SUPERNET.noncing = 0; |
||||
|
printf("finished noncing for (%s)\n",destpoint); |
||||
|
free(destpoint); |
||||
|
} |
||||
|
|
||||
|
void recv_nonces(void *_ptr) |
||||
|
{ |
||||
|
int32_t i,j,n; cJSON *json,*item,*array,*nonces; char *jsonstr; struct applicant_info A,*ptr = _ptr; |
||||
|
if ( ptr->startflag != 0 ) |
||||
|
{ |
||||
|
double endmilli = milliseconds() + 60000; |
||||
|
printf("start receiving nonces\n"); |
||||
|
SUPERNET.numnonces = 0; |
||||
|
while ( milliseconds() < endmilli ) |
||||
|
msleep(1000); |
||||
|
printf("finished.%d recv_nonces\n",SUPERNET.numnonces); |
||||
|
free(ptr); |
||||
|
if ( (n= SUPERNET.numnonces) > 0 ) |
||||
|
{ |
||||
|
json = cJSON_CreateObject(); |
||||
|
array = cJSON_CreateArray(); |
||||
|
while ( n > 0 ) |
||||
|
{ |
||||
|
A = SUPERNET.responses[0]; |
||||
|
item = cJSON_CreateObject(); |
||||
|
nonces = cJSON_CreateArray(); |
||||
|
SUPERNET.responses[0] = SUPERNET.responses[--n]; |
||||
|
for (i=0; i<=n; i++) |
||||
|
{ |
||||
|
if ( strcmp(A.lbendpoint,SUPERNET.responses[i].lbendpoint) == 0 ) |
||||
|
{ |
||||
|
cJSON_AddItemToArray(nonces,cJSON_CreateNumber(SUPERNET.responses[i].nonce)); |
||||
|
memset(&SUPERNET.responses[i],0,sizeof(SUPERNET.responses[i])); |
||||
|
} |
||||
|
} |
||||
|
for (j=0,i=1; i<n; i++) |
||||
|
if ( SUPERNET.responses[i].senderbits != 0 ) |
||||
|
SUPERNET.responses[j++] = SUPERNET.responses[i]; |
||||
|
n = j; |
||||
|
cJSON_AddItemToObject(item,"lbendpoint",cJSON_CreateString(A.lbendpoint)); |
||||
|
cJSON_AddItemToObject(item,"relaypoint",cJSON_CreateString(A.relayendpoint)); |
||||
|
cJSON_AddItemToObject(item,"glboalpoint",cJSON_CreateString(A.globalendpoint)); |
||||
|
cJSON_AddItemToObject(item,"nonces",nonces); |
||||
|
cJSON_AddItemToArray(array,item); |
||||
|
} |
||||
|
cJSON_AddItemToObject(json,"peers",array); |
||||
|
cJSON_AddItemToObject(json,"lbendpoint",cJSON_CreateString(SUPERNET.lbendpoint)); |
||||
|
cJSON_AddItemToObject(json,"relaypoint",cJSON_CreateString(SUPERNET.relayendpoint)); |
||||
|
cJSON_AddItemToObject(json,"glboalpoint",cJSON_CreateString(SUPERNET.globalendpoint)); |
||||
|
jsonstr = cJSON_Print(json), _stripwhite(jsonstr,' '); |
||||
|
printf("%s\n",jsonstr); |
||||
|
if ( SUPERNET.peersjson != 0 ) |
||||
|
free_json(SUPERNET.peersjson); |
||||
|
SUPERNET.peersjson = json; |
||||
|
} |
||||
|
SUPERNET.noncing = 0; |
||||
|
SUPERNET.numnonces = 0; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
SUPERNET.responses = realloc(SUPERNET.responses,(sizeof(*SUPERNET.responses) * (SUPERNET.numnonces + 1))); |
||||
|
SUPERNET.responses[SUPERNET.numnonces++] = *ptr; |
||||
|
fprintf(stderr,"%d: got nonce.%u from %llu %s/%s/%s\n",SUPERNET.numnonces,ptr->nonce,(long long)ptr->senderbits,ptr->lbendpoint,ptr->relayendpoint,ptr->globalendpoint); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void protocols_register(char *NXTaddr,char *protocol,char *endpoint,int32_t disconnect) |
||||
|
{ |
||||
|
/*uint64_t nxt64bits = conv_acctstr(NXTaddr);
|
||||
|
if ( disconnect == 0 ) |
||||
|
dKV777_write(SUPERNET.relays,SUPERNET.protocols,nxt64bits,protocol,(int32_t)strlen(protocol)+1,endpoint,(int32_t)strlen(endpoint)+1); |
||||
|
else dKV777_delete(SUPERNET.relays,SUPERNET.protocols,nxt64bits,protocol,(int32_t)strlen(protocol)+1);*/ |
||||
|
printf("need to %s protocol %s with %s\n",disconnect==0?"register":"disconnect",protocol,endpoint); |
||||
|
} |
||||
|
|
||||
|
int32_t PLUGNAME(_process_json)(char *forwarder,char *sender,int32_t valid,struct plugin_info *plugin,uint64_t tag,char *retbuf,int32_t maxlen,char *origjsonstr,cJSON *origjson,int32_t initflag,char *tokenstr) |
||||
|
{ |
||||
|
char *resultstr,*retstr = 0,*methodstr,*jsonstr,*destplugin,*submethod; struct destbuf tagstr,endpoint; |
||||
|
cJSON *retjson,*json,*tokenobj; uint32_t nonce; |
||||
|
struct applicant_info apply; |
||||
|
retbuf[0] = 0; |
||||
|
if ( tokenstr == 0 ) |
||||
|
tokenstr = ""; |
||||
|
if ( is_cJSON_Array(origjson) != 0 && cJSON_GetArraySize(origjson) == 2 ) |
||||
|
json = cJSON_GetArrayItem(origjson,0), jsonstr = cJSON_Print(json), _stripwhite(jsonstr,' '); |
||||
|
else json = origjson, jsonstr = origjsonstr; |
||||
|
if ( Debuglevel > 2 ) |
||||
|
printf("<<<<<<<<<<<< INSIDE relays PLUGIN! process %s [(%s).(%s)]\n",plugin->name,jsonstr,tokenstr); |
||||
|
if ( initflag > 0 ) |
||||
|
{ |
||||
|
// configure settings
|
||||
|
RELAYS.readyflag = 1; |
||||
|
plugin->allowremote = 1; |
||||
|
plugin->sleepmillis = 100; |
||||
|
strcpy(retbuf,"{\"result\":\"initflag > 0\"}"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if ( plugin_result(retbuf,json,tag) > 0 ) |
||||
|
return((int32_t)strlen(retbuf)); |
||||
|
resultstr = cJSON_str(cJSON_GetObjectItem(json,"result")); |
||||
|
methodstr = cJSON_str(cJSON_GetObjectItem(json,"method")); |
||||
|
destplugin = cJSON_str(cJSON_GetObjectItem(json,"destplugin")); |
||||
|
submethod = cJSON_str(cJSON_GetObjectItem(json,"submethod")); |
||||
|
if ( methodstr == 0 || methodstr[0] == 0 ) |
||||
|
{ |
||||
|
printf("(%s) has not method\n",jsonstr); |
||||
|
return(0); |
||||
|
} |
||||
|
//fprintf(stderr,"RELAYS methodstr.(%s) (%s)\n",methodstr,jsonstr);
|
||||
|
if ( resultstr != 0 && strcmp(resultstr,"registered") == 0 ) |
||||
|
{ |
||||
|
plugin->registered = 1; |
||||
|
strcpy(retbuf,"{\"result\":\"activated\"}"); |
||||
|
} |
||||
|
#ifdef INSIDE_MGW |
||||
|
else if ( strcmp(methodstr,"msigaddr") == 0 ) |
||||
|
{ |
||||
|
char *devMGW_command(char *jsonstr,cJSON *json); |
||||
|
if ( SUPERNET.gatewayid >= 0 ) |
||||
|
retstr = devMGW_command(jsonstr,json); |
||||
|
} |
||||
|
#endif |
||||
|
else |
||||
|
{ |
||||
|
strcpy(retbuf,"{\"result\":\"relay command under construction\"}"); |
||||
|
if ( strcmp(methodstr,"list") == 0 ) |
||||
|
retstr = relays_jsonstr(jsonstr,json); |
||||
|
else if ( strcmp(methodstr,"telepathy") == 0 ) |
||||
|
{ |
||||
|
sprintf(retbuf,"%s",jsonstr); |
||||
|
} |
||||
|
else if ( strcmp(methodstr,"busdata") == 0 ) |
||||
|
{ |
||||
|
retstr = busdata_sync(&nonce,jsonstr,cJSON_str(cJSON_GetObjectItem(json,"broadcast")),0); |
||||
|
// {"plugin":"relay","method":"busdata","destplugin":"relay","submethod":"join","broadcast":"join","endpoint":""}
|
||||
|
} |
||||
|
else if ( strcmp(methodstr,"allservices") == 0 ) |
||||
|
{ |
||||
|
if ( (retjson= serviceprovider_json()) != 0 ) |
||||
|
{ |
||||
|
retstr = cJSON_Print(retjson), _stripwhite(retstr,' '); |
||||
|
free_json(retjson); |
||||
|
//printf("got.(%s)\n",retstr);
|
||||
|
} else printf("null serviceprovider_json()\n"); |
||||
|
} |
||||
|
else if ( strcmp(methodstr,"protocol") == 0 || strcmp(methodstr,"allprotocols") == 0 ) |
||||
|
{ |
||||
|
if ( strcmp(methodstr,"protocol") == 0 && valid > 0 ) |
||||
|
protocols_register(sender,jstr(json,"protocol"),jstr(json,"endpoint"),jint(json,"disconnect")); |
||||
|
if ( (retjson= protocols_json(jstr(json,"protocol"))) != 0 ) |
||||
|
{ |
||||
|
retstr = cJSON_Print(retjson), _stripwhite(retstr,' '); |
||||
|
free_json(retjson); |
||||
|
} else printf("null protocols_json()\n"); |
||||
|
} |
||||
|
else if ( strcmp(methodstr,"join") == 0 ) |
||||
|
{ |
||||
|
if ( SUPERNET.noncing == 0 ) |
||||
|
{ |
||||
|
copy_cJSON(&tagstr,cJSON_GetObjectItem(json,"tag")); |
||||
|
copy_cJSON(&endpoint,cJSON_GetObjectItem(json,"endpoint")); |
||||
|
SUPERNET.noncing = 1; |
||||
|
if ( SUPERNET.iamrelay != 0 ) |
||||
|
{ |
||||
|
portable_thread_create((void *)calc_nonces,clonestr(endpoint.buf)); |
||||
|
sprintf(retbuf,"{\"result\":\"noncing\",\"endpoint\":\"%s\"}",endpoint.buf); |
||||
|
} |
||||
|
//fprintf(stderr,"join or nonce.(%s)\n",retbuf);
|
||||
|
} |
||||
|
} |
||||
|
else if ( strcmp(methodstr,"nonce") == 0 ) |
||||
|
{ |
||||
|
struct destbuf endpointbuf,senderbuf,destpoint,relaypoint,globalpoint,noncestr; |
||||
|
memset(&apply,0,sizeof(apply)); |
||||
|
copy_cJSON(&destpoint,cJSON_GetObjectItem(json,"destpoint")); |
||||
|
copy_cJSON(&endpointbuf,cJSON_GetObjectItem(json,"lbendpoint")); |
||||
|
copy_cJSON(&relaypoint,cJSON_GetObjectItem(json,"relaypoint")); |
||||
|
copy_cJSON(&globalpoint,cJSON_GetObjectItem(json,"globalpoint")); |
||||
|
copy_cJSON(&senderbuf,cJSON_GetObjectItem(json,"NXT")); |
||||
|
if ( SUPERNET.noncing != 0 && strcmp(SUPERNET.lbendpoint,destpoint.buf) == 0 ) |
||||
|
{ |
||||
|
if ( endpointbuf.buf[0] != 0 && tokenstr != 0 && tokenstr[0] != 0 && (tokenobj= cJSON_Parse(tokenstr)) != 0 ) |
||||
|
{ |
||||
|
strcpy(apply.lbendpoint,endpointbuf.buf); |
||||
|
strcpy(apply.relayendpoint,relaypoint.buf); |
||||
|
strcpy(apply.globalendpoint,globalpoint.buf); |
||||
|
apply.senderbits = calc_nxt64bits(senderbuf.buf); |
||||
|
copy_cJSON(&noncestr,cJSON_GetObjectItem(tokenobj,"nonce")); |
||||
|
if ( noncestr.buf[0] != 0 ) |
||||
|
apply.nonce = (uint32_t)calc_nxt64bits(noncestr.buf); |
||||
|
//printf("tokenobj.(%s) -> nonce.%u\n",tokenstr,apply.nonce);
|
||||
|
free_json(tokenobj); |
||||
|
recv_nonces(&apply); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return(plugin_copyretstr(retbuf,maxlen,retstr)); |
||||
|
} |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,701 @@ |
|||||
|
/******************************************************************************
|
||||
|
* Copyright © 2014-2015 The SuperNET Developers. * |
||||
|
* * |
||||
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
||||
|
* the top-level directory of this distribution for the individual copyright * |
||||
|
* holder information and the developer policies on copyright and licensing. * |
||||
|
* * |
||||
|
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
||||
|
* SuperNET software, including this file may be copied, modified, propagated * |
||||
|
* or distributed except according to the terms contained in the LICENSE file * |
||||
|
* * |
||||
|
* Removal or modification of this copyright notice is prohibited. * |
||||
|
* * |
||||
|
******************************************************************************/ |
||||
|
#ifdef notyet |
||||
|
|
||||
|
#ifdef DEFINES_ONLY |
||||
|
#ifndef crypto777_system777_h |
||||
|
#define crypto777_system777_h |
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <stdint.h> |
||||
|
#include <unistd.h> |
||||
|
#include <curl/curl.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/time.h> |
||||
|
//#include "../includes/miniupnp/miniwget.h"
|
||||
|
//#include "../includes/miniupnp/miniupnpc.h"
|
||||
|
//#include "../includes/miniupnp/upnpcommands.h"
|
||||
|
//#include "../includes/miniupnp/upnperrors.h"
|
||||
|
#include "../includes/uthash.h" |
||||
|
#include "../includes/cJSON.h" |
||||
|
#include "../utils/utils777.c" |
||||
|
#include "../utils/inet.c" |
||||
|
#include "../includes/utlist.h" |
||||
|
#include "../includes/nonportable.h" |
||||
|
#include "../includes/portable777.h" |
||||
|
|
||||
|
|
||||
|
#define SUPERNET_PORT 7777 |
||||
|
#define LB_OFFSET 1 |
||||
|
#define PUBGLOBALS_OFFSET 2 |
||||
|
#define PUBRELAYS_OFFSET 3 |
||||
|
#define SUPERNET_APIENDPOINT "tcp://127.0.0.1:7776"
|
||||
|
|
||||
|
#define nn_errstr() nn_strerror(nn_errno()) |
||||
|
|
||||
|
extern int32_t Debuglevel; |
||||
|
|
||||
|
#ifndef MIN |
||||
|
#define MIN(x,y) (((x)<=(y)) ? (x) : (y)) |
||||
|
#endif |
||||
|
#ifndef MAX |
||||
|
#define MAX(x,y) (((x)>=(y)) ? (x) : (y)) |
||||
|
#endif |
||||
|
typedef int32_t (*ptm)(int32_t,char *args[]); |
||||
|
// nonportable functions needed in the OS specific directory
|
||||
|
int32_t is_bundled_plugin(char *plugin); |
||||
|
|
||||
|
struct sendendpoints { int32_t push,rep,pub,survey; }; |
||||
|
struct recvendpoints { int32_t pull,req,sub,respond; }; |
||||
|
struct biendpoints { int32_t bus,pair; }; |
||||
|
struct allendpoints { struct sendendpoints send; struct recvendpoints recv; struct biendpoints both; }; |
||||
|
union endpoints { int32_t all[sizeof(struct allendpoints) / sizeof(int32_t)]; struct allendpoints socks; }; |
||||
|
struct db777_entry { UT_hash_handle hh; uint32_t allocsize,valuelen,valuesize,keylen:30,linked:1,dirty:1; uint8_t value[]; }; |
||||
|
|
||||
|
struct db777 |
||||
|
{ |
||||
|
void *db,*asyncdb; |
||||
|
portable_mutex_t mutex; |
||||
|
struct db777_entry *table; |
||||
|
int32_t reqsock,valuesize,matrixentries; |
||||
|
uint32_t start_RTblocknum; |
||||
|
void **matrix; char *dirty; |
||||
|
char compression[8],dbname[32],name[16],coinstr[16],flags; |
||||
|
void *ctl,*env; char namestr[32],restoredir[512],argspecialpath[512],argsubdir[512],restorelogdir[512],argname[512],argcompression[512],backupdir[512]; |
||||
|
uint8_t checkbuf[10000000]; |
||||
|
}; |
||||
|
|
||||
|
struct env777 |
||||
|
{ |
||||
|
char coinstr[16],subdir[64]; |
||||
|
void *ctl,*env,*transactions; |
||||
|
struct db777 dbs[16]; |
||||
|
int32_t numdbs,needbackup,lastbackup,currentbackup,matrixentries; |
||||
|
uint32_t start_RTblocknum; |
||||
|
}; |
||||
|
|
||||
|
#define DEFAULT_APISLEEP 100 // milliseconds
|
||||
|
#define NUM_PLUGINTAGS 8192 |
||||
|
struct applicant_info { uint64_t senderbits; uint32_t nonce; char startflag,lbendpoint[128],relayendpoint[128],globalendpoint[128]; }; |
||||
|
|
||||
|
struct SuperNET_info |
||||
|
{ |
||||
|
char WEBSOCKETD[1024],NXTAPIURL[1024],NXTSERVER[1024],DBPATH[1024],DATADIR[1024],transport[16],BACKUPS[512],SERVICENXT[64]; |
||||
|
char myipaddr[64],myNXTacct[64],myNXTaddr[64],NXTACCT[64],NXTADDR[64],NXTACCTSECRET[8192],SERVICESECRET[8192],userhome[512],hostname[512]; |
||||
|
uint64_t my64bits; uint8_t myprivkey[32],mypubkey[32]; |
||||
|
uint32_t myipbits,nonces[512],numnonces; struct applicant_info *responses; cJSON *peersjson; char lbendpoint[128],relayendpoint[128],globalendpoint[128]; |
||||
|
int32_t usessl,ismainnet,Debuglevel,SuperNET_retval,APISLEEP,gatewayid,numgateways,readyflag,UPNP,iamrelay,disableNXT,NXTconfirms,automatch,PLUGINTIMEOUT,ppid,noncing,pullsock,telepathicdelay,peggy,idlegap,exchangeidle,recvtimeout; |
||||
|
uint16_t port,serviceport,pangeaport; |
||||
|
uint64_t tags[NUM_PLUGINTAGS][3]; |
||||
|
struct kv777 *PM,*rawPM,*protocols,*alias,*services,*invoices,*NXTtxids,*NXTaccts; |
||||
|
struct dKV777 *relays; |
||||
|
cJSON *argjson; |
||||
|
//#ifdef INSIDE_MGW
|
||||
|
// struct env777 *DBs;
|
||||
|
//#endif
|
||||
|
}; extern struct SuperNET_info SUPERNET; |
||||
|
|
||||
|
struct coins_info |
||||
|
{ |
||||
|
int32_t num,readyflag,slicei; |
||||
|
cJSON *argjson; |
||||
|
struct coin777 **LIST; |
||||
|
// this will be at the end of the plugins structure and will be called with all zeros to _init
|
||||
|
}; extern struct coins_info COINS; |
||||
|
|
||||
|
struct db777_info |
||||
|
{ |
||||
|
char PATH[1024],RAMDISK[1024]; |
||||
|
int32_t numdbs,readyflag; |
||||
|
struct db777 *DBS[1024]; |
||||
|
}; extern struct db777_info SOPHIA; |
||||
|
|
||||
|
#define MAX_MGWSERVERS 16 |
||||
|
struct MGW_info |
||||
|
{ |
||||
|
char PATH[1024],serverips[MAX_MGWSERVERS][64],bridgeipaddr[64],bridgeacct[64]; |
||||
|
uint64_t srv64bits[MAX_MGWSERVERS],issuers[64]; |
||||
|
int32_t M,numissuers,readyflag,port; |
||||
|
union endpoints all; |
||||
|
uint32_t numrecv,numsent; |
||||
|
}; extern struct MGW_info MGW; |
||||
|
|
||||
|
#define MAX_RAMCHAINS 128 |
||||
|
struct ramchain_info |
||||
|
{ |
||||
|
char PATH[1024],coins[MAX_RAMCHAINS][16],pullnode[64]; |
||||
|
double lastupdate[MAX_RAMCHAINS]; |
||||
|
union endpoints all; |
||||
|
int32_t num,readyflag,fastmode,verifyspends; |
||||
|
// this will be at the end of the plugins structure and will be called with all zeros to _init
|
||||
|
}; extern struct ramchain_info RAMCHAINS; |
||||
|
|
||||
|
struct cashier_info |
||||
|
{ |
||||
|
int32_t readyflag; |
||||
|
}; extern struct cashier_info CASHIER; |
||||
|
|
||||
|
struct prices_info |
||||
|
{ |
||||
|
int32_t readyflag; |
||||
|
}; extern struct prices_info PRICES; |
||||
|
|
||||
|
#define DEFAULT_PEGGYDAYS 21 |
||||
|
#define PEGGY_LOCK 1 |
||||
|
#define PEGGY_REDEEM 2 |
||||
|
struct teleport_info |
||||
|
{ |
||||
|
uint64_t availablemilli; |
||||
|
int32_t readyflag; |
||||
|
}; extern struct teleport_info TELEPORT; |
||||
|
|
||||
|
struct InstantDEX_info |
||||
|
{ |
||||
|
int32_t readyflag,numhist; |
||||
|
struct txinds777_info *history; |
||||
|
}; extern struct InstantDEX_info INSTANTDEX; |
||||
|
|
||||
|
#define MAX_SERVERNAME 128 |
||||
|
struct relayargs |
||||
|
{ |
||||
|
//char *(*commandprocessor)(struct relayargs *args,uint8_t *msg,int32_t len);
|
||||
|
char name[16],endpoint[MAX_SERVERNAME]; |
||||
|
int32_t sock,type,bindflag,sendtimeout,recvtimeout; |
||||
|
}; |
||||
|
struct _relay_info { int32_t sock,num,mytype,desttype; struct endpoint connections[1 << CONNECTION_NUMBITS]; }; |
||||
|
struct direct_connection { char handler[16]; struct endpoint epbits; int32_t sock; }; |
||||
|
|
||||
|
struct relay_info |
||||
|
{ |
||||
|
struct _relay_info active; |
||||
|
struct nn_pollfd pfd[16]; |
||||
|
int32_t readyflag,subclient,lbclient,lbserver,servicesock,pubglobal,pubrelays,numservers; |
||||
|
}; extern struct relay_info RELAYS; |
||||
|
|
||||
|
void expand_epbits(char *endpoint,struct endpoint epbits); |
||||
|
struct endpoint calc_epbits(char *transport,uint32_t ipbits,uint16_t port,int32_t type); |
||||
|
int upnpredirect(const char* eport, const char* iport, const char* proto, const char* description); |
||||
|
|
||||
|
void *myaligned_alloc(uint64_t allocsize); |
||||
|
int32_t aligned_free(void *alignedptr); |
||||
|
|
||||
|
void *portable_thread_create(void *funcp,void *argp); |
||||
|
void randombytes(unsigned char *x,long xlen); |
||||
|
double milliseconds(void); |
||||
|
void msleep(uint32_t milliseconds); |
||||
|
#define portable_sleep(n) msleep((n) * 1000) |
||||
|
|
||||
|
int32_t getline777(char *line,int32_t max); |
||||
|
char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *args); |
||||
|
uint16_t wait_for_myipaddr(char *ipaddr); |
||||
|
void process_userinput(char *line); |
||||
|
|
||||
|
int32_t init_socket(char *suffix,char *typestr,int32_t type,char *_bindaddr,char *_connectaddr,int32_t timeout); |
||||
|
int32_t shutdown_plugsocks(union endpoints *socks); |
||||
|
int32_t nn_local_broadcast(int32_t pushsock,uint64_t instanceid,int32_t flags,uint8_t *retstr,int32_t len); |
||||
|
//char *poll_local_endpoints(int32_t *lenp,int32_t pullsock);
|
||||
|
struct endpoint nn_directepbits(char *retbuf,char *transport,char *ipaddr,uint16_t port); |
||||
|
int32_t nn_directsend(struct endpoint epbits,uint8_t *msg,int32_t len); |
||||
|
|
||||
|
void ensure_directory(char *dirname); |
||||
|
uint32_t is_ipaddr(char *str); |
||||
|
|
||||
|
uint64_t calc_ipbits(char *ipaddr); |
||||
|
void expand_ipbits(char *ipaddr,uint64_t ipbits); |
||||
|
char *ipbits_str(uint64_t ipbits); |
||||
|
char *ipbits_str2(uint64_t ipbits); |
||||
|
struct sockaddr_in conv_ipbits(uint64_t ipbits); |
||||
|
uint32_t conv_domainname(char *ipaddr,char *domain); |
||||
|
int32_t ismyaddress(char *server); |
||||
|
|
||||
|
void set_endpointaddr(char *transport,char *endpoint,char *domain,uint16_t port,int32_t type); |
||||
|
int32_t nn_portoffset(int32_t type); |
||||
|
|
||||
|
char *plugin_method(int32_t sock,char **retstrp,int32_t localaccess,char *plugin,char *method,uint64_t daemonid,uint64_t instanceid,char *origargstr,int32_t len,int32_t timeout,char *tokenstr); |
||||
|
//char *nn_direct(char *ipaddr,uint8_t *data,int32_t len);
|
||||
|
//char *nn_publish(uint8_t *data,int32_t len,int32_t nostr);
|
||||
|
//char *nn_allrelays(uint8_t *data,int32_t len,int32_t timeoutmillis,char *localresult);
|
||||
|
char *nn_loadbalanced(uint8_t *data,int32_t len); |
||||
|
char *relays_jsonstr(char *jsonstr,cJSON *argjson); |
||||
|
struct daemon_info *find_daemoninfo(int32_t *indp,char *name,uint64_t daemonid,uint64_t instanceid); |
||||
|
int32_t init_pingpong_queue(struct pingpong_queue *ppq,char *name,int32_t (*action)(),queue_t *destq,queue_t *errorq); |
||||
|
int32_t process_pingpong_queue(struct pingpong_queue *ppq,void *argptr); |
||||
|
uint8_t *replace_forwarder(char *pluginbuf,uint8_t *data,int32_t *datalenp); |
||||
|
int32_t nn_socket_status(int32_t sock,int32_t timeoutmillis); |
||||
|
|
||||
|
char *nn_busdata_processor(uint8_t *msg,int32_t len); |
||||
|
void busdata_init(int32_t sendtimeout,int32_t recvtimeout,int32_t firstiter); |
||||
|
int32_t busdata_poll(); |
||||
|
char *busdata_sync(uint32_t *noncep,char *jsonstr,char *broadcastmode,char *destNXTaddr); |
||||
|
int32_t parse_ipaddr(char *ipaddr,char *ip_port); |
||||
|
int32_t construct_tokenized_req(uint32_t *noncep,char *tokenized,char *cmdjson,char *NXTACCTSECRET,char *broadcastmode); |
||||
|
int32_t validate_token(struct destbuf *forwarder,struct destbuf *pubkey,struct destbuf *NXTaddr,char *tokenizedtxt,int32_t strictflag); |
||||
|
uint32_t busdata_nonce(int32_t *leveragep,char *str,char *broadcaststr,int32_t maxmillis,uint32_t nonce); |
||||
|
int32_t nonce_leverage(char *broadcaststr); |
||||
|
char *get_broadcastmode(cJSON *json,char *broadcastmode); |
||||
|
cJSON *serviceprovider_json(); |
||||
|
int32_t nn_createsocket(char *endpoint,int32_t bindflag,char *name,int32_t type,uint16_t port,int32_t sendtimeout,int32_t recvtimeout); |
||||
|
int32_t nn_lbsocket(int32_t maxmillis,int32_t port,uint16_t globalport,uint16_t relaysport); |
||||
|
int32_t OS_init(); |
||||
|
int32_t nn_settimeouts(int32_t sock,int32_t sendtimeout,int32_t recvtimeout); |
||||
|
int32_t is_duplicate_tag(uint64_t tag); |
||||
|
void portable_OS_init(); |
||||
|
void telepathic_PM(char *destNXT,char *PM); |
||||
|
extern queue_t TelepathyQ; |
||||
|
uint16_t parse_endpoint(int32_t *ip6flagp,char *transport,char *ipbuf,char *retbuf,char *endpoint,uint16_t default_port); |
||||
|
cJSON *protocols_json(char *protocol); |
||||
|
|
||||
|
uint64_t millistamp(); |
||||
|
uint32_t calc_timeslot(int32_t millidiff,int32_t timeres); |
||||
|
|
||||
|
int32_t _add_related(uint64_t *assetids,int32_t n,uint64_t refbaseid,uint64_t refrelid,int32_t exchangeid,uint64_t baseid,uint64_t relid); |
||||
|
int32_t add_related(uint64_t *assetids,int32_t n,uint64_t supported[][2],long num,int32_t exchangeid,uint64_t baseid,uint64_t relid); |
||||
|
int32_t add_NXT_assetids(uint64_t *assetids,int32_t n,uint64_t assetid); |
||||
|
int32_t add_exchange_assetid(uint64_t *assetids,int32_t n,uint64_t baseid,uint64_t relid,int32_t exchangeid); |
||||
|
int32_t add_exchange_assetids(uint64_t *assetids,int32_t n,uint64_t refassetid,uint64_t baseid,uint64_t relid,int32_t exchangeid,char *symbolmap[][8],int32_t numsymbols); |
||||
|
double prices777_baseprice(uint32_t timestamp,int32_t basenum); |
||||
|
|
||||
|
|
||||
|
#define MAXTIMEDIFF 60 |
||||
|
|
||||
|
#endif |
||||
|
#else |
||||
|
#ifndef crypto777_system777_c |
||||
|
#define crypto777_system777_c |
||||
|
|
||||
|
#ifndef crypto777_system777_h |
||||
|
#define DEFINES_ONLY |
||||
|
#include "../common/system777.c" |
||||
|
#undef DEFINES_ONLY |
||||
|
#endif |
||||
|
|
||||
|
struct nn_clock |
||||
|
{ |
||||
|
uint64_t last_tsc; |
||||
|
uint64_t last_time; |
||||
|
} Global_timer; |
||||
|
|
||||
|
void msleep(uint32_t milliseconds) |
||||
|
{ |
||||
|
void nn_sleep (int milliseconds); |
||||
|
nn_sleep(milliseconds); |
||||
|
} |
||||
|
typedef void (portable_thread_func)(void *); |
||||
|
/*
|
||||
|
double milliseconds() |
||||
|
{ |
||||
|
uint64_t nn_clock_now (struct nn_clock *self); |
||||
|
return(nn_clock_now(&Global_timer)); |
||||
|
}*/ |
||||
|
|
||||
|
|
||||
|
struct nn_thread |
||||
|
{ |
||||
|
portable_thread_func *routine; |
||||
|
void *arg; |
||||
|
void *handle; |
||||
|
}; |
||||
|
void nn_thread_init (struct nn_thread *self,portable_thread_func *routine,void *arg); |
||||
|
void nn_thread_term (struct nn_thread *self); |
||||
|
|
||||
|
/*static uint64_t _align16(uint64_t ptrval) { if ( (ptrval & 15) != 0 ) ptrval += 16 - (ptrval & 15); return(ptrval); }
|
||||
|
|
||||
|
void *myaligned_alloc(uint64_t allocsize) |
||||
|
{ |
||||
|
void *ptr,*realptr; uint64_t tmp; |
||||
|
realptr = calloc(1,allocsize + 16 + sizeof(realptr)); |
||||
|
tmp = _align16((long)realptr + sizeof(ptr)); |
||||
|
memcpy(&ptr,&tmp,sizeof(ptr)); |
||||
|
memcpy((void *)((long)ptr - sizeof(realptr)),&realptr,sizeof(realptr)); |
||||
|
printf("aligned_alloc(%llu) realptr.%p -> ptr.%p, diff.%ld\n",(long long)allocsize,realptr,ptr,((long)ptr - (long)realptr)); |
||||
|
return(ptr); |
||||
|
} |
||||
|
|
||||
|
int32_t aligned_free(void *ptr) |
||||
|
{ |
||||
|
void *realptr; |
||||
|
long diff; |
||||
|
if ( ((long)ptr & 0xf) != 0 ) |
||||
|
{ |
||||
|
printf("misaligned ptr.%p being aligned_free\n",ptr); |
||||
|
return(-1); |
||||
|
} |
||||
|
memcpy(&realptr,(void *)((long)ptr - sizeof(realptr)),sizeof(realptr)); |
||||
|
diff = ((long)ptr - (long)realptr); |
||||
|
if ( diff < (long)sizeof(ptr) || diff > 32 ) |
||||
|
{ |
||||
|
printf("ptr %p and realptr %p too far apart %ld\n",ptr,realptr,diff); |
||||
|
return(-2); |
||||
|
} |
||||
|
//printf("aligned_free: ptr %p -> realptr %p %ld\n",ptr,realptr,diff);
|
||||
|
free(realptr); |
||||
|
return(0); |
||||
|
}*/ |
||||
|
|
||||
|
void *portable_thread_create(void *funcp,void *argp) |
||||
|
{ |
||||
|
//void nn_thread_term(struct nn_thread *self);
|
||||
|
void nn_thread_init(struct nn_thread *self,portable_thread_func *routine,void *arg); |
||||
|
struct nn_thread *ptr; |
||||
|
ptr = (struct nn_thread *)malloc(sizeof(*ptr)); |
||||
|
nn_thread_init(ptr,(portable_thread_func *)funcp,argp); |
||||
|
return(ptr); |
||||
|
} |
||||
|
/*
|
||||
|
struct queueitem *queueitem(char *str) |
||||
|
{ |
||||
|
struct queueitem *item = calloc(1,sizeof(struct queueitem) + strlen(str) + 1); |
||||
|
strcpy((char *)((long)item + sizeof(struct queueitem)),str); |
||||
|
return(item); |
||||
|
} |
||||
|
|
||||
|
struct queueitem *queuedata(void *data,int32_t datalen) |
||||
|
{ |
||||
|
struct queueitem *item = calloc(1,sizeof(struct queueitem) + datalen); |
||||
|
memcpy((char *)((long)item + sizeof(struct queueitem)),data,datalen); |
||||
|
return(item); |
||||
|
} |
||||
|
|
||||
|
void free_queueitem(void *itemptr) { free((void *)((long)itemptr - sizeof(struct queueitem))); } |
||||
|
|
||||
|
void lock_queue(queue_t *queue) |
||||
|
{ |
||||
|
if ( queue->initflag == 0 ) |
||||
|
{ |
||||
|
portable_mutex_init(&queue->mutex); |
||||
|
queue->initflag = 1; |
||||
|
} |
||||
|
portable_mutex_lock(&queue->mutex); |
||||
|
} |
||||
|
|
||||
|
void queue_enqueue(char *name,queue_t *queue,struct queueitem *item) |
||||
|
{ |
||||
|
if ( queue->list == 0 && name != 0 && name[0] != 0 ) |
||||
|
safecopy(queue->name,name,sizeof(queue->name)); |
||||
|
if ( item == 0 ) |
||||
|
{ |
||||
|
printf("FATAL type error: queueing empty value\n");//, getchar();
|
||||
|
return; |
||||
|
} |
||||
|
lock_queue(queue); |
||||
|
DL_APPEND(queue->list,item); |
||||
|
portable_mutex_unlock(&queue->mutex); |
||||
|
//printf("name.(%s) append.%p list.%p\n",name,item,queue->list);
|
||||
|
} |
||||
|
|
||||
|
void *queue_dequeue(queue_t *queue,int32_t offsetflag) |
||||
|
{ |
||||
|
struct queueitem *item = 0; |
||||
|
lock_queue(queue); |
||||
|
if ( queue->list != 0 ) |
||||
|
{ |
||||
|
item = queue->list; |
||||
|
DL_DELETE(queue->list,item); |
||||
|
//printf("name.(%s) dequeue.%p list.%p\n",queue->name,item,queue->list);
|
||||
|
} |
||||
|
portable_mutex_unlock(&queue->mutex); |
||||
|
if ( item != 0 && offsetflag != 0 ) |
||||
|
return((void *)((long)item + sizeof(struct queueitem))); |
||||
|
else return(item); |
||||
|
} |
||||
|
|
||||
|
void *queue_delete(queue_t *queue,struct queueitem *copy,int32_t copysize) |
||||
|
{ |
||||
|
struct queueitem *item = 0; |
||||
|
lock_queue(queue); |
||||
|
if ( queue->list != 0 ) |
||||
|
{ |
||||
|
DL_FOREACH(queue->list,item) |
||||
|
{ |
||||
|
if ( memcmp((void *)((long)item + sizeof(struct queueitem)),(void *)((long)item + sizeof(struct queueitem)),copysize) == 0 ) |
||||
|
{ |
||||
|
DL_DELETE(queue->list,item); |
||||
|
return(item); |
||||
|
} |
||||
|
} |
||||
|
//printf("name.(%s) dequeue.%p list.%p\n",queue->name,item,queue->list);
|
||||
|
} |
||||
|
portable_mutex_unlock(&queue->mutex); |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
void *queue_free(queue_t *queue) |
||||
|
{ |
||||
|
struct queueitem *item = 0; |
||||
|
lock_queue(queue); |
||||
|
if ( queue->list != 0 ) |
||||
|
{ |
||||
|
DL_FOREACH(queue->list,item) |
||||
|
{ |
||||
|
DL_DELETE(queue->list,item); |
||||
|
free(item); |
||||
|
} |
||||
|
//printf("name.(%s) dequeue.%p list.%p\n",queue->name,item,queue->list);
|
||||
|
} |
||||
|
portable_mutex_unlock(&queue->mutex); |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
void *queue_clone(queue_t *clone,queue_t *queue,int32_t size) |
||||
|
{ |
||||
|
struct queueitem *ptr,*item = 0; |
||||
|
lock_queue(queue); |
||||
|
if ( queue->list != 0 ) |
||||
|
{ |
||||
|
DL_FOREACH(queue->list,item) |
||||
|
{ |
||||
|
ptr = calloc(1,sizeof(*ptr)); |
||||
|
memcpy(ptr,item,size); |
||||
|
queue_enqueue(queue->name,clone,ptr); |
||||
|
} |
||||
|
//printf("name.(%s) dequeue.%p list.%p\n",queue->name,item,queue->list);
|
||||
|
} |
||||
|
portable_mutex_unlock(&queue->mutex); |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
int32_t queue_size(queue_t *queue) |
||||
|
{ |
||||
|
int32_t count = 0; |
||||
|
struct queueitem *tmp; |
||||
|
lock_queue(queue); |
||||
|
DL_COUNT(queue->list,tmp,count); |
||||
|
portable_mutex_unlock(&queue->mutex); |
||||
|
return count; |
||||
|
}*/ |
||||
|
|
||||
|
int32_t init_pingpong_queue(struct pingpong_queue *ppq,char *name,int32_t (*action)(),queue_t *destq,queue_t *errorq) |
||||
|
{ |
||||
|
ppq->name = name; |
||||
|
ppq->destqueue = destq; |
||||
|
ppq->errorqueue = errorq; |
||||
|
ppq->action = action; |
||||
|
ppq->offset = 1; |
||||
|
return(queue_size(&ppq->pingpong[0]) + queue_size(&ppq->pingpong[1])); // init mutex side effect
|
||||
|
} |
||||
|
|
||||
|
// seems a bit wastefull to do all the two iter queueing/dequeuing with threadlock overhead
|
||||
|
// however, there is assumed to be plenty of CPU time relative to actual blockchain events
|
||||
|
// also this method allows for adding of parallel threads without worry
|
||||
|
int32_t process_pingpong_queue(struct pingpong_queue *ppq,void *argptr) |
||||
|
{ |
||||
|
int32_t iter,retval,freeflag = 0; |
||||
|
void *ptr; |
||||
|
//printf("%p process_pingpong_queue.%s %d %d\n",ppq,ppq->name,queue_size(&ppq->pingpong[0]),queue_size(&ppq->pingpong[1]));
|
||||
|
for (iter=0; iter<2; iter++) |
||||
|
{ |
||||
|
while ( (ptr= queue_dequeue(&ppq->pingpong[iter],ppq->offset)) != 0 ) |
||||
|
{ |
||||
|
if ( Debuglevel > 2 ) |
||||
|
printf("%s pingpong[%d].%p action.%p\n",ppq->name,iter,ptr,ppq->action); |
||||
|
retval = (*ppq->action)(&ptr,argptr); |
||||
|
if ( retval == 0 ) |
||||
|
queue_enqueue(ppq->name,&ppq->pingpong[iter ^ 1],ptr,0); |
||||
|
else if ( ptr != 0 ) |
||||
|
{ |
||||
|
if ( retval < 0 ) |
||||
|
{ |
||||
|
if ( Debuglevel > 0 ) |
||||
|
printf("%s iter.%d errorqueue %p vs %p\n",ppq->name,iter,ppq->errorqueue,&ppq->pingpong[0]); |
||||
|
if ( ppq->errorqueue == &ppq->pingpong[0] ) |
||||
|
queue_enqueue(ppq->name,&ppq->pingpong[iter ^ 1],ptr,0); |
||||
|
else if ( ppq->errorqueue != 0 ) |
||||
|
queue_enqueue(ppq->name,ppq->errorqueue,ptr,0); |
||||
|
else freeflag = 1; |
||||
|
} |
||||
|
else if ( ppq->destqueue != 0 ) |
||||
|
{ |
||||
|
if ( Debuglevel > 0 ) |
||||
|
printf("%s iter.%d destqueue %p vs %p\n",ppq->name,iter,ppq->destqueue,&ppq->pingpong[0]); |
||||
|
if ( ppq->destqueue == &ppq->pingpong[0] ) |
||||
|
queue_enqueue(ppq->name,&ppq->pingpong[iter ^ 1],ptr,0); |
||||
|
else if ( ppq->destqueue != 0 ) |
||||
|
queue_enqueue(ppq->name,ppq->destqueue,ptr,0); |
||||
|
else freeflag = 1; |
||||
|
} |
||||
|
if ( freeflag != 0 ) |
||||
|
{ |
||||
|
if ( ppq->offset == 0 ) |
||||
|
free(ptr); |
||||
|
else free_queueitem(ptr); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return(queue_size(&ppq->pingpong[0]) + queue_size(&ppq->pingpong[0])); |
||||
|
} |
||||
|
|
||||
|
uint16_t wait_for_myipaddr(char *ipaddr) |
||||
|
{ |
||||
|
uint16_t port = 0; |
||||
|
printf("need a portable way to find IP addr\n"); |
||||
|
//getchar();
|
||||
|
return(port); |
||||
|
} |
||||
|
|
||||
|
int32_t ismyaddress(char *server) |
||||
|
{ |
||||
|
char ipaddr[64]; uint32_t ipbits; |
||||
|
if ( strncmp(server,"tcp://",6) == 0 ) |
||||
|
server += 6; |
||||
|
else if ( strncmp(server,"ws://",5) == 0 ) |
||||
|
server += 5; |
||||
|
if ( (ipbits= is_ipaddr(server)) != 0 ) |
||||
|
{ |
||||
|
if ( strcmp(server,SUPERNET.myipaddr) == 0 || calc_ipbits(SUPERNET.myipaddr) == ipbits ) |
||||
|
{ |
||||
|
printf("(%s) MATCHES me (%s)\n",server,SUPERNET.myipaddr); |
||||
|
return(1); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if ( SUPERNET.hostname[0] != 0 && strcmp(SUPERNET.hostname,server) == 0 ) |
||||
|
return(1); |
||||
|
else if ( (ipbits= conv_domainname(ipaddr,server)) != 0 || SUPERNET.my64bits == ipbits ) |
||||
|
return(1); |
||||
|
else if ( (strcmp(SUPERNET.myipaddr,ipaddr) == 0 || strcmp(SUPERNET.hostname,ipaddr) == 0) ) |
||||
|
return(1); |
||||
|
} |
||||
|
//printf("(%s) is not me (%s)\n",server,SUPERNET.myipaddr);
|
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
int32_t nn_local_broadcast(int32_t sock,uint64_t instanceid,int32_t flags,uint8_t *retstr,int32_t len) |
||||
|
{ |
||||
|
int32_t i,sendlen,errs = 0; |
||||
|
if ( sock >= 0 ) |
||||
|
{ |
||||
|
for (i=0; i<10; i++) |
||||
|
if ( (nn_socket_status(sock,1) & NN_POLLOUT) != 0 ) |
||||
|
break; |
||||
|
if ( (sendlen= nn_send(sock,(char *)retstr,len,0)) <= 0 ) |
||||
|
errs++, printf("sending to socket.%d sendlen.%d len.%d (%s) [%s]\n",sock,sendlen,len,nn_strerror(nn_errno()),retstr); |
||||
|
else if ( Debuglevel > 2 ) |
||||
|
printf("nn_local_broadcast SENT.(%s) len.%d sendlen.%d vs strlen.%ld instanceid.%llu -> sock.%d\n",retstr,len,sendlen,(long)strlen((char *)retstr),(long long)instanceid,sock); |
||||
|
} |
||||
|
return(errs); |
||||
|
} |
||||
|
|
||||
|
int32_t plugin_result(char *retbuf,cJSON *json,uint64_t tag) |
||||
|
{ |
||||
|
char *error,*result; |
||||
|
error = cJSON_str(cJSON_GetObjectItem(json,"error")); |
||||
|
result = cJSON_str(cJSON_GetObjectItem(json,"result")); |
||||
|
if ( error != 0 || result != 0 ) |
||||
|
{ |
||||
|
sprintf(retbuf,"{\"result\":\"completed\",\"tag\":\"%llu\"}",(long long)tag); |
||||
|
return(1); |
||||
|
} |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
double estimate_completion(double startmilli,int32_t processed,int32_t numleft) |
||||
|
{ |
||||
|
double elapsed,rate; |
||||
|
if ( processed <= 0 ) |
||||
|
return(0.); |
||||
|
elapsed = (milliseconds() - startmilli); |
||||
|
rate = (elapsed / processed); |
||||
|
if ( rate <= 0. ) |
||||
|
return(0.); |
||||
|
//printf("numleft %d rate %f\n",numleft,rate);
|
||||
|
return(numleft * rate); |
||||
|
} |
||||
|
|
||||
|
void clear_alloc_space(struct alloc_space *mem,int32_t alignflag) |
||||
|
{ |
||||
|
memset(mem->ptr,0,mem->size); |
||||
|
mem->used = 0; |
||||
|
mem->alignflag = alignflag; |
||||
|
} |
||||
|
|
||||
|
void rewind_alloc_space(struct alloc_space *mem,int32_t flags) |
||||
|
{ |
||||
|
if ( (flags & 1) != 0 ) |
||||
|
clear_alloc_space(mem,1); |
||||
|
else mem->used = 0; |
||||
|
mem->alignflag = ((flags & ~1) != 0); |
||||
|
} |
||||
|
|
||||
|
struct alloc_space *init_alloc_space(struct alloc_space *mem,void *ptr,long size,int32_t flags) |
||||
|
{ |
||||
|
if ( mem == 0 ) |
||||
|
mem = calloc(1,size + sizeof(*mem)), ptr = mem->space; |
||||
|
mem->size = size; |
||||
|
mem->ptr = ptr; |
||||
|
rewind_alloc_space(mem,flags); |
||||
|
return(mem); |
||||
|
} |
||||
|
|
||||
|
void *memalloc(struct alloc_space *mem,long size,int32_t clearflag) |
||||
|
{ |
||||
|
void *ptr = 0; |
||||
|
if ( (mem->used + size) > mem->size ) |
||||
|
{ |
||||
|
printf("alloc: (mem->used %ld + %ld size) %ld > %ld mem->size\n",mem->used,size,(mem->used + size),mem->size); |
||||
|
while ( 1 ) |
||||
|
portable_sleep(1); |
||||
|
} |
||||
|
ptr = (void *)((long)mem->ptr + mem->used); |
||||
|
mem->used += size; |
||||
|
if ( clearflag != 0 ) |
||||
|
memset(ptr,0,size); |
||||
|
if ( mem->alignflag != 0 && (mem->used & 0xf) != 0 ) |
||||
|
mem->used += 0x10 - (mem->used & 0xf); |
||||
|
return(ptr); |
||||
|
} |
||||
|
|
||||
|
uint64_t millistamp() { return(time(NULL)*1000 + ((uint64_t)milliseconds() % 1000)); } |
||||
|
uint32_t calc_timeslot(int32_t millidiff,int32_t timeres) { return(((uint32_t)(millistamp() + (timeres>>1) + millidiff) / timeres)); } |
||||
|
|
||||
|
#define GENESISACCT "1739068987193023818" // NXT-MRCC-2YLS-8M54-3CMAJ
|
||||
|
#define GENESISPUBKEYSTR "1259ec21d31a30898d7cd1609f80d9668b4778e3d97e941044b39f0c44d2e51b" |
||||
|
#define GENESISPRIVKEYSTR "88a71671a6edd987ad9e9097428fc3f169decba3ac8f10da7b24e0ca16803b70" |
||||
|
#define GENESIS_SECRET "It was a bright cold day in April, and the clocks were striking thirteen." |
||||
|
|
||||
|
void portable_OS_init() |
||||
|
{ |
||||
|
uint64_t conv_NXTpassword(unsigned char *mysecret,unsigned char *mypublic,uint8_t *pass,int32_t passlen); |
||||
|
char hexstr[65]; bits256 privkey,pubkey; uint64_t nxt64bits=0; extern bits256 GENESIS_PUBKEY,GENESIS_PRIVKEY; |
||||
|
void SaM_PrepareIndices(); |
||||
|
decode_hex(GENESIS_PUBKEY.bytes,sizeof(GENESIS_PUBKEY),GENESISPUBKEYSTR); |
||||
|
decode_hex(GENESIS_PRIVKEY.bytes,sizeof(GENESIS_PRIVKEY),GENESISPRIVKEYSTR); |
||||
|
printf("decoded genesis 123\n"); |
||||
|
nxt64bits = conv_NXTpassword(privkey.bytes,pubkey.bytes,(void *)GENESIS_SECRET,(int32_t)strlen(GENESIS_SECRET)); |
||||
|
char pubkeystr[67]; uint8_t pub[33]; |
||||
|
hexstr[0]= 0; |
||||
|
btc_priv2pub(pub,GENESIS_PRIVKEY.bytes); |
||||
|
init_hexbytes_noT(pubkeystr,pub,33); |
||||
|
printf("pubkey.%s %llx\n",pubkeystr,*(long long *)pub); |
||||
|
printf("%s conv_NXTpassword %llu\n",__TIME__,(long long)nxt64bits); |
||||
|
if ( nxt64bits != calc_nxt64bits(GENESISACCT) ) |
||||
|
printf("GENESIS_ACCT mismatch %llu != %llu\n",(long long)nxt64bits,(long long)calc_nxt64bits(GENESISACCT)); |
||||
|
if ( memcmp(GENESIS_PUBKEY.bytes,pubkey.bytes,sizeof(pubkey)) != 0 ) |
||||
|
printf("GENESIS_PUBKEY mismatch %llu != %llu\n",(long long)GENESIS_PUBKEY.txid,(long long)pubkey.txid); |
||||
|
if ( memcmp(GENESIS_PRIVKEY.bytes,privkey.bytes,sizeof(privkey)) != 0 ) |
||||
|
{ |
||||
|
init_hexbytes_noT(hexstr,privkey.bytes,sizeof(privkey)); |
||||
|
//printf("%s GENESIS_PRIVKEY mismatch %llu != %llu\n",hexstr,(long long)GENESIS_PRIVKEY.txid,(long long)privkey.txid);
|
||||
|
} |
||||
|
printf("%s GENESIS_PRIVKEY %llx GENESIS_PUBKEY %llx\n",hexstr,(long long)GENESIS_PRIVKEY.txid,(long long)GENESIS_PUBKEY.txid); |
||||
|
OS_init(); |
||||
|
curl_global_init(CURL_GLOBAL_ALL); //init the curl session
|
||||
|
SaM_PrepareIndices(); |
||||
|
} |
||||
|
#endif |
||||
|
#endif |
||||
|
|
||||
|
#endif |
@ -0,0 +1,485 @@ |
|||||
|
/******************************************************************************
|
||||
|
* Copyright © 2014-2015 The SuperNET Developers. * |
||||
|
* * |
||||
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
||||
|
* the top-level directory of this distribution for the individual copyright * |
||||
|
* holder information and the developer policies on copyright and licensing. * |
||||
|
* * |
||||
|
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
||||
|
* SuperNET software, including this file may be copied, modified, propagated * |
||||
|
* or distributed except according to the terms contained in the LICENSE file * |
||||
|
* * |
||||
|
* Removal or modification of this copyright notice is prohibited. * |
||||
|
* * |
||||
|
******************************************************************************/ |
||||
|
#ifdef notyet |
||||
|
|
||||
|
#define BUNDLED |
||||
|
#define PLUGINSTR "teleport" |
||||
|
#define PLUGNAME(NAME) teleport ## NAME |
||||
|
#define STRUCTNAME struct PLUGNAME(_info) |
||||
|
#define STRINGIFY(NAME) #NAME |
||||
|
#define PLUGIN_EXTRASIZE sizeof(STRUCTNAME) |
||||
|
|
||||
|
#define DEFINES_ONLY |
||||
|
#include "../coins/coins777.c" |
||||
|
#include "../agents/plugin777.c" |
||||
|
#include "../utils/bits777.c" |
||||
|
#undef DEFINES_ONLY |
||||
|
|
||||
|
#define NXTPRIVACY_COINADDR "RELiMDcxPeAT85acmeAEEX3M2omZRax4ft" |
||||
|
|
||||
|
STRUCTNAME TELEPORT; |
||||
|
struct invoice_info { uint8_t hash[32]; }; |
||||
|
struct telepod { char txid[256],privkey[256],podaddr[256],script[512]; uint64_t value; int32_t vout,numconfirms; }; |
||||
|
|
||||
|
int32_t telepathic_remotejson(cJSON *json) |
||||
|
{ |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
int32_t telepathic_remotestr(char *pmstr) |
||||
|
{ |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
int32_t telepathic_remotebinary(char *hexstr,void *data,int32_t datalen) |
||||
|
{ |
||||
|
char *signedtx,*cointxid; struct coin777 *coin = coin777_find("BTCD",0); |
||||
|
if ( SUPERNET.iamrelay != 0 && coin != 0 ) |
||||
|
{ |
||||
|
signedtx = malloc(datalen*2 + 16); |
||||
|
sprintf(signedtx,"[\"%s\"]",hexstr); |
||||
|
if ( (cointxid= bitcoind_passthru("BTCD",coin->serverport,coin->userpass,"sendrawtransaction",signedtx)) != 0 ) |
||||
|
{ |
||||
|
printf(">>>>>>>>>>>>> BROADCAST.(%s) (%s)\n",signedtx,cointxid); |
||||
|
free(cointxid); |
||||
|
} |
||||
|
free(signedtx); |
||||
|
} |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
int32_t teleport_idle(struct plugin_info *plugin) |
||||
|
{ |
||||
|
int32_t pmlen; char *pmstr,*decoded; cJSON *decodedjson; uint64_t r; |
||||
|
if ( TELEPORT.availablemilli == 0 ) |
||||
|
{ |
||||
|
randombytes((void *)&r,sizeof(r)); |
||||
|
TELEPORT.availablemilli = (uint64_t)(milliseconds() + SUPERNET.telepathicdelay + (r % SUPERNET.telepathicdelay)); |
||||
|
} |
||||
|
if ( milliseconds() > TELEPORT.availablemilli && (pmstr= queue_dequeue(&TelepathyQ,1)) != 0 ) |
||||
|
{ |
||||
|
if ( is_hexstr(pmstr) != 0 ) |
||||
|
{ |
||||
|
pmlen = (int32_t)strlen(pmstr); |
||||
|
decoded = malloc((pmlen >> 1) + 1); |
||||
|
decode_hex((void *)decoded,pmlen,pmstr); |
||||
|
decoded[pmlen] = 0; |
||||
|
if ( (decodedjson= cJSON_Parse(decoded)) != 0 ) |
||||
|
{ |
||||
|
telepathic_remotejson(decodedjson); |
||||
|
free_json(decodedjson); |
||||
|
} else telepathic_remotebinary(pmstr,decoded,pmlen); |
||||
|
free(decoded); |
||||
|
} else telepathic_remotestr(pmstr); |
||||
|
TELEPORT.availablemilli = 0; |
||||
|
free_queueitem(pmstr); |
||||
|
return(1); |
||||
|
} |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
uint64_t parse_unspent_json(struct telepod *pod,struct coin777 *coin,cJSON *json) |
||||
|
{ |
||||
|
char args[MAX_JSON_FIELD+2],*privkey = 0; uint64_t amount = 0; struct destbuf tmp; |
||||
|
copy_cJSON(&tmp,cJSON_GetObjectItem(json,"txid")), safecopy(pod->txid,tmp.buf,sizeof(pod->txid)); |
||||
|
copy_cJSON(&tmp,cJSON_GetObjectItem(json,"address")), safecopy(pod->podaddr,tmp.buf,sizeof(pod->podaddr));; |
||||
|
copy_cJSON(&tmp,cJSON_GetObjectItem(json,"scriptPubKey")), safecopy(pod->script,tmp.buf,sizeof(pod->script));; |
||||
|
amount = (uint64_t)(SATOSHIDEN * get_API_float(cJSON_GetObjectItem(json,"amount"))); |
||||
|
pod->vout = juint(json,"vout"); |
||||
|
pod->numconfirms = juint(json,"confirmations"); |
||||
|
if ( pod->txid[0] != 0 && pod->podaddr[0] != 0 && pod->script[0] != 0 && amount != 0 && pod->vout >= 0 ) |
||||
|
{ |
||||
|
sprintf(args,"[\"%s\"]",pod->podaddr); |
||||
|
privkey = bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"dumpprivkey",args); |
||||
|
if ( privkey != 0 ) |
||||
|
{ |
||||
|
strcpy(pod->privkey,privkey); |
||||
|
free(privkey); |
||||
|
} |
||||
|
else amount = 0, fprintf(stderr,"error podaddr.(%s) cant find privkey\n",pod->podaddr); |
||||
|
} else printf("illegal unspent output: (%s) (%s) (%s) %.8f %d\n",pod->txid,pod->podaddr,pod->script,dstr(amount),pod->vout); |
||||
|
return(amount); |
||||
|
} |
||||
|
|
||||
|
char *teleport_OP_RETURN(int32_t opreturn,char *rawtx,char *opreturnhexstr,int32_t oldtx_format) |
||||
|
{ |
||||
|
char scriptstr[1024],*retstr = 0; long len; struct cointx_info *cointx; struct rawvout *vout; |
||||
|
if ( (cointx= _decode_rawtransaction(rawtx,oldtx_format)) != 0 ) |
||||
|
{ |
||||
|
vout = &cointx->outputs[opreturn]; |
||||
|
safecopy(vout->script,scriptstr,sizeof(vout->script)); |
||||
|
len = (strlen(rawtx) + strlen(opreturnhexstr)) * 2; |
||||
|
retstr = calloc(1,len + 1); |
||||
|
safecopy(cointx->outputs[opreturn].script,opreturnhexstr,sizeof(cointx->outputs[opreturn].script)); |
||||
|
if ( Debuglevel > 1 ) |
||||
|
disp_cointx(cointx); |
||||
|
printf("teleport_OP_RETURN: vout.%d %p (%s) (%s)\n",opreturn,vout,vout->script,cointx->outputs[opreturn].script); |
||||
|
if ( _emit_cointx(retstr,len,cointx,oldtx_format) < 0 ) |
||||
|
free(retstr), retstr = 0; |
||||
|
free(cointx); |
||||
|
} else printf("error teleport_OP_RETURN\n"); |
||||
|
return(retstr); |
||||
|
} |
||||
|
|
||||
|
char *teleport_sign_rawbytes(int32_t *completedp,char *signedbytes,long max,char *coinstr,char *serverport,char *userpass,char *rawbytes) |
||||
|
{ |
||||
|
char *hexstr,*retstr = 0; cJSON *json,*compobj; |
||||
|
*completedp = 0; |
||||
|
if ( (retstr= bitcoind_passthru(coinstr,serverport,userpass,"signrawtransaction",rawbytes)) != 0 ) |
||||
|
{ |
||||
|
if ( (json= cJSON_Parse(retstr)) != 0 ) |
||||
|
{ |
||||
|
if ( (compobj= cJSON_GetObjectItem(json,"complete")) != 0 ) |
||||
|
*completedp = ((compobj->type&0xff) == cJSON_True); |
||||
|
if ( (hexstr= cJSON_str(cJSON_GetObjectItem(json,"hex"))) != 0 ) |
||||
|
{ |
||||
|
if ( strlen(hexstr) > max ) |
||||
|
printf("sign_rawbytes: strlen(hexstr) %d > %ld destize (%s)\n",(int32_t)strlen(hexstr),max,retstr), free(retstr), retstr = 0; |
||||
|
else strcpy(signedbytes,hexstr); |
||||
|
} else printf("no hex.(%s)\n",retstr); |
||||
|
free_json(json); |
||||
|
} else printf("json parse error.(%s)\n",retstr); |
||||
|
} else printf("error signing rawtx\n"); |
||||
|
return(retstr); |
||||
|
} |
||||
|
|
||||
|
char *teleport_calctransaction(struct coin777 *coin,cJSON *vinsobj,cJSON *voutsobj,cJSON *privkeys,int32_t opreturnvout,char *opreturnhexstr) |
||||
|
{ |
||||
|
char *paramstr,*txbytes,*txbytes2,*signedtx; int32_t completed; cJSON *array = cJSON_CreateArray(); |
||||
|
cJSON_AddItemToArray(array,cJSON_Duplicate(vinsobj,1)); |
||||
|
cJSON_AddItemToArray(array,cJSON_Duplicate(voutsobj,1)); |
||||
|
paramstr = cJSON_Print(array), free_json(array), _stripwhite(paramstr,' '); |
||||
|
txbytes = bitcoind_passthru(coin->name,coin->serverport,coin->userpass,"createrawtransaction",paramstr); |
||||
|
free(paramstr); |
||||
|
if ( txbytes == 0 ) |
||||
|
return(0); |
||||
|
printf("got txbytes.(%s) opreturn.%d\n",txbytes,opreturnvout); |
||||
|
if ( opreturnvout >= 0 && opreturnhexstr != 0 && opreturnhexstr[0] != 0 ) |
||||
|
{ |
||||
|
if ( (txbytes2= teleport_OP_RETURN(opreturnvout,txbytes,opreturnhexstr,coin->mgw.oldtx_format)) == 0 ) |
||||
|
{ |
||||
|
fprintf(stderr,"error replacing with OP_RETURN.%s txout.%d (%s)\n",coin->name,opreturnvout,txbytes); |
||||
|
free(txbytes); |
||||
|
return(0); |
||||
|
} |
||||
|
free(txbytes); |
||||
|
txbytes = txbytes2, txbytes2 = 0; |
||||
|
printf("teleport opreturn txbytes.(%s)\n",txbytes); |
||||
|
} |
||||
|
array = cJSON_CreateArray(); |
||||
|
cJSON_AddItemToArray(array,cJSON_CreateString(txbytes)); |
||||
|
cJSON_AddItemToArray(array,vinsobj); |
||||
|
cJSON_AddItemToArray(array,privkeys); |
||||
|
paramstr = cJSON_Print(array), free_json(array); |
||||
|
signedtx = calloc(1,strlen(paramstr)*4 + 4096); |
||||
|
if ( (signedtx= teleport_sign_rawbytes(&completed,signedtx,strlen(signedtx),coin->name,coin->serverport,coin->userpass,paramstr)) != 0 ) |
||||
|
{ |
||||
|
if ( completed == 0 ) |
||||
|
{ |
||||
|
printf("error signing completed.%d (%s)\n",completed,signedtx); |
||||
|
free(signedtx), signedtx = 0; |
||||
|
} |
||||
|
} else fprintf(stderr,"error _sign_localtx.(%s)\n",txbytes); |
||||
|
free(paramstr); |
||||
|
return(signedtx); |
||||
|
} |
||||
|
|
||||
|
char *teleport_paymentstr(struct coin777 *coin,char *funding,char *paymentaddr,uint64_t payment,char *opreturnhexstr) |
||||
|
{ |
||||
|
int32_t i,n; uint64_t value,change = 0,sum = 0; cJSON *array,*item,*input,*vins,*vouts,*privkeys; |
||||
|
char *retstr,*changeaddr=0,params[512],buf[1024]; struct telepod pod; struct destbuf acct; |
||||
|
if ( coin != 0 && payment != 0 && paymentaddr != 0 && paymentaddr[0] != 0 ) |
||||
|
{ |
||||
|
vins = cJSON_CreateObject(), vouts = cJSON_CreateObject(), privkeys = cJSON_CreateObject(); |
||||
|
sprintf(params,"%d, 99999999",coin->minconfirms); |
||||
|
retstr = bitcoind_passthru(coin->name,coin->serverport,coin->userpass,"listunspent",params); |
||||
|
if ( retstr != 0 && retstr[0] != 0 && (array= cJSON_Parse(retstr)) != 0 ) |
||||
|
{ |
||||
|
if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) |
||||
|
{ |
||||
|
for (i=0; i<n; i++) |
||||
|
{ |
||||
|
item = cJSON_GetArrayItem(array,i); |
||||
|
copy_cJSON(&acct,cJSON_GetObjectItem(item,"account")); |
||||
|
if ( funding == 0 || strcmp(acct.buf,funding) == 0 ) |
||||
|
{ |
||||
|
if ( (value= parse_unspent_json(&pod,coin,item)) != 0 ) |
||||
|
{ |
||||
|
sum += value; |
||||
|
input = cJSON_CreateObject(); |
||||
|
cJSON_AddItemToObject(input,"txid",cJSON_CreateString(pod.txid)); |
||||
|
cJSON_AddItemToObject(input,"vout",cJSON_CreateNumber(pod.vout)); |
||||
|
cJSON_AddItemToArray(vins,input); |
||||
|
cJSON_AddItemToArray(privkeys,cJSON_CreateString(pod.privkey)); |
||||
|
if ( sum >= payment ) |
||||
|
{ |
||||
|
if ( sum > payment ) |
||||
|
{ |
||||
|
change = (sum - payment); |
||||
|
sprintf(buf,"[\"%s\"]",funding); |
||||
|
if ( (changeaddr= bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"getnewaddress",buf)) == 0 ) |
||||
|
payment += change; |
||||
|
} |
||||
|
cJSON_AddItemToObject(vouts,paymentaddr,cJSON_CreateNumber(dstr(payment))); |
||||
|
if ( changeaddr != 0 ) |
||||
|
cJSON_AddItemToObject(vouts,changeaddr,cJSON_CreateNumber(dstr(change))); |
||||
|
free_json(array), free(retstr); |
||||
|
return(teleport_calctransaction(coin,vins,vouts,privkeys,0,opreturnhexstr)); |
||||
|
} |
||||
|
} else fprintf(stderr,"parse_unspent null\n"); |
||||
|
} |
||||
|
} |
||||
|
} free_json(array); |
||||
|
} free(retstr); |
||||
|
} |
||||
|
printf("teleport_paymentstr: cant find enough unspents from (%s)\n",funding!=0?funding:"all accounts"); |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
void telepathic_PM(char *destNXT,char *PM) |
||||
|
{ |
||||
|
uint32_t nonce; char *retstr,*jsonstr; cJSON *json = cJSON_CreateObject(); |
||||
|
//./BitcoinDarkd SuperNET '{"plugin":"relay","method":"PM","broadcast":"allnodes","PM":"testms4gff2","destNXT":"NXT-9Q52-L9PY-8C2A-339MB"}'
|
||||
|
cJSON_AddItemToObject(json,"agent",cJSON_CreateString("relay")); |
||||
|
cJSON_AddItemToObject(json,"method",cJSON_CreateString("PM")); |
||||
|
cJSON_AddItemToObject(json,"broadcast",cJSON_CreateString("allnodes")); |
||||
|
cJSON_AddItemToObject(json,"destNXT",cJSON_CreateString(destNXT)); |
||||
|
cJSON_AddItemToObject(json,"PM",cJSON_CreateString(PM)); |
||||
|
jsonstr = cJSON_Print(json), _stripwhite(jsonstr,' '), free_json(json); |
||||
|
if ( (retstr= busdata_sync(&nonce,jsonstr,"allnodes",destNXT)) != 0 ) |
||||
|
free(retstr); |
||||
|
free(jsonstr); |
||||
|
} |
||||
|
|
||||
|
char *teleport_calctxbytes(char *funding,uint64_t nxt64bits,uint16_t minlockdays,uint16_t maxlockdays,char *invoices,char *peggy,int32_t numunits,char *paymentaddr) |
||||
|
{ |
||||
|
int32_t peggy_calc_opreturn(uint64_t namebits,char *opreturnhexstr,uint64_t nxt64bits,uint16_t minlockdays,uint16_t maxlockdays,char *invoices,int32_t command,int32_t numunits,char *paymentaddr); |
||||
|
struct coin777 *coin; |
||||
|
if ( strcmp(peggy,"BTCD") == 0 && (coin= coin777_find(peggy,1)) != 0 ) |
||||
|
{ |
||||
|
if ( funding == 0 ) |
||||
|
funding = "telepods"; |
||||
|
else if ( strcmp(funding,"any") == 0 ) |
||||
|
funding = 0; |
||||
|
//if ( peggy_calc_opreturn(stringbits(peggy),opreturnhexstr,nxt64bits,minlockdays,maxlockdays,invoices,PEGGY_LOCK,numunits,paymentaddr) == 0 )
|
||||
|
// return(teleport_paymentstr(coin,funding,paymentaddr,(uint64_t)numunits * SATOSHIDEN,opreturnhexstr));
|
||||
|
//else
|
||||
|
return(clonestr("{\"error\":\"peggy_calc_opreturn errpr\"}")); |
||||
|
} else return(clonestr("{\"error\":\"only BTCD for now\"}")); |
||||
|
} |
||||
|
|
||||
|
void *invoice_iterator(struct kv777 *kv,void *_ptr,void *key,int32_t keysize,void *value,int32_t valuesize) |
||||
|
{ |
||||
|
char numstr[64]; struct invoice_info *invoice = key; cJSON *item,*array = _ptr; |
||||
|
if ( keysize == sizeof(*invoice) ) |
||||
|
{ |
||||
|
item = cJSON_CreateObject(); |
||||
|
init_hexbytes_noT(numstr,invoice->hash,sizeof(invoice->hash)); |
||||
|
cJSON_AddItemToObject(item,"invoicebits",cJSON_CreateString(numstr)); |
||||
|
cJSON_AddItemToObject(item,"status",cJSON_CreateNumber(*(int32_t *)value)); |
||||
|
cJSON_AddItemToArray(array,item); |
||||
|
return(0); |
||||
|
} |
||||
|
printf("unexpected services entry size.%d/%d vs %d? abort serviceprovider_iterator\n",keysize,valuesize,(int32_t)sizeof(*invoice)); |
||||
|
return(KV777_ABORTITERATOR); |
||||
|
} |
||||
|
|
||||
|
cJSON *teleport_invoices(uint8_t *invoicebits) |
||||
|
{ |
||||
|
cJSON *array,*json = cJSON_CreateObject(); |
||||
|
if ( SUPERNET.invoices != 0 ) |
||||
|
{ |
||||
|
array = cJSON_CreateArray(); |
||||
|
kv777_iterate(SUPERNET.invoices,array,0,invoice_iterator); |
||||
|
cJSON_AddItemToObject(json,"invoices",array); |
||||
|
return(json); |
||||
|
} |
||||
|
return(json); |
||||
|
} |
||||
|
|
||||
|
cJSON *teleport_calcinvoicebits(int32_t *nump,uint8_t invoicebits[][32],uint8_t claimbits[][32],cJSON **claimsp,int16_t lockdays,int32_t numunits) |
||||
|
{ |
||||
|
/*int32_t peggy_numinvoices(int32_t numunits);
|
||||
|
int32_t incr,n = 0; cJSON *claims,*invoices; char invoicestr[65],claimstr[65]; |
||||
|
claims = cJSON_CreateArray(), invoices = cJSON_CreateArray(); |
||||
|
for (incr=10000; incr>0; incr/=10) |
||||
|
{ |
||||
|
while ( numunits >= incr ) |
||||
|
{ |
||||
|
bits777_invoicehash(lockdays,invoicebits[n],claimbits[n]); |
||||
|
init_hexbytes_noT(claimstr,claimbits[n],32); |
||||
|
init_hexbytes_noT(invoicestr,invoicebits[n],32); |
||||
|
cJSON_AddItemToArray(claims,cJSON_CreateString(claimstr)); |
||||
|
cJSON_AddItemToArray(invoices,cJSON_CreateString(invoicestr)); |
||||
|
numunits -= incr, n++; |
||||
|
} |
||||
|
} |
||||
|
*claimsp = claims, *nump = n; |
||||
|
if ( n != peggy_numinvoices(numunits) ) |
||||
|
{ |
||||
|
printf("teleport_calcinvoicebits: unexpected mismatch.%d != %d\n",n,peggy_numinvoices(numunits)); |
||||
|
free_json(invoices), free_json(claims); |
||||
|
return(0); |
||||
|
} |
||||
|
return(invoices);*/ |
||||
|
return(0); |
||||
|
} |
||||
|
|
||||
|
char *teleport_invoicestatus(char *invoicestr) |
||||
|
{ |
||||
|
char *jsonstr; uint8_t invoicebits[1024]; int32_t len; cJSON *json = cJSON_CreateObject(); |
||||
|
cJSON_AddItemToObject(json,"invoicebits",cJSON_CreateString(invoicestr)); |
||||
|
len = (int32_t)strlen(invoicestr) >> 1, decode_hex(invoicebits,len,invoicestr); |
||||
|
cJSON_AddItemToObject(json,"status",teleport_invoices(invoicebits)); |
||||
|
jsonstr = cJSON_Print(json), _stripwhite(jsonstr,' '), free_json(json); |
||||
|
return(jsonstr); |
||||
|
} |
||||
|
|
||||
|
char *teleport_sendinvoice(cJSON *origjson,char *peggy,int32_t lockdays,int32_t numunits,char *validation,char *paymentaddr,char *destNXT,char *delivery) |
||||
|
{ |
||||
|
uint8_t invoicebits[512][32],claimbits[512][32]; char *jsonstr; cJSON *array,*json,*item,*item2; |
||||
|
uint64_t nxt64bits; int32_t i,valuesize,numinvoices; uint8_t *value; |
||||
|
if ( delivery == 0 ) |
||||
|
delivery = "PM"; |
||||
|
if ( strcmp(delivery,"broadcast") == 0 ) |
||||
|
destNXT = GENESISACCT, delivery = "PM"; |
||||
|
if ( peggy != 0 && numunits != 0 && validation != 0 && paymentaddr != 0 ) |
||||
|
{ |
||||
|
json = cJSON_CreateObject(), array = cJSON_CreateArray(); |
||||
|
cJSON_AddItemToArray(array,origjson); |
||||
|
if ( (item= teleport_calcinvoicebits(&numinvoices,invoicebits,claimbits,&item2,lockdays,numunits)) != 0 ) |
||||
|
cJSON_AddItemToObject(json,"invoices",item), cJSON_AddItemToObject(json,"claims",item2); |
||||
|
else cJSON_AddItemToObject(json,"error",cJSON_CreateString("cant create invoices")); |
||||
|
cJSON_AddItemToArray(array,json); |
||||
|
jsonstr = cJSON_Print(array), _stripwhite(jsonstr,' '), free_json(array); |
||||
|
if ( item != 0 ) |
||||
|
{ |
||||
|
if ( strcmp(delivery,"PM") == 0 ) |
||||
|
{ |
||||
|
if ( destNXT != 0 && (nxt64bits= conv_acctstr(destNXT)) != 0 ) |
||||
|
{ |
||||
|
telepathic_PM(destNXT,jsonstr); |
||||
|
if ( SUPERNET.invoices != 0 ) |
||||
|
{ |
||||
|
valuesize = (int32_t)strlen(jsonstr) + 1; |
||||
|
value = calloc(1,valuesize + sizeof(int32_t)); |
||||
|
memcpy(&value[sizeof(int32_t)],jsonstr,valuesize); |
||||
|
for (i=0; i<numinvoices; i++) |
||||
|
{ |
||||
|
if ( kv777_write(SUPERNET.invoices,invoicebits[i],32,value,valuesize + sizeof(int32_t)) == 0 ) |
||||
|
{ |
||||
|
free(jsonstr); |
||||
|
return(clonestr("{\"error\":\"kv777_write error\"}")); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
else printf("teleport_sendinvoice: warning need destNXT address to send PM\n"); |
||||
|
} |
||||
|
} |
||||
|
return(jsonstr); |
||||
|
} |
||||
|
else return(clonestr("{\"error\":\"invalid invoice parameter\"}")); |
||||
|
} |
||||
|
|
||||
|
char *teleport_sendmoney(char *funding,char *lockNXT,uint16_t minlockdays,uint16_t maxlockdays,char *invoices,char *peggy,int32_t numunits,char *paymentaddr,char *destNXT,char *delivery) |
||||
|
{ |
||||
|
char *txbytes,*jsonstr = 0; uint64_t nxt64bits = 0; cJSON *json = cJSON_CreateObject(); |
||||
|
if ( lockNXT != 0 && lockNXT[0] != 0 ) |
||||
|
nxt64bits = conv_acctstr(lockNXT); |
||||
|
if ( delivery == 0 ) |
||||
|
delivery = "PM"; |
||||
|
if ( strcmp(delivery,"broadcast") == 0 ) |
||||
|
destNXT = GENESISACCT, delivery = "PM"; |
||||
|
if ( numunits > 0 && (txbytes= teleport_calctxbytes(funding,nxt64bits,minlockdays,maxlockdays,invoices,peggy,numunits,paymentaddr)) != 0 ) |
||||
|
{ |
||||
|
jsonstr = cJSON_Print(json), _stripwhite(jsonstr,' '), free_json(json); |
||||
|
if ( strcmp(delivery,"PM") == 0 ) |
||||
|
{ |
||||
|
if ( destNXT != 0 && conv_acctstr(destNXT) != 0 ) |
||||
|
telepathic_PM(destNXT,txbytes); |
||||
|
else printf("teleport_sendinvoice: warning need destNXT address to send PM\n"); |
||||
|
} |
||||
|
free(txbytes); |
||||
|
} else jsonstr = clonestr("{\"error\":\"illegal teleport sendmoney parameter\"}"); |
||||
|
return(jsonstr); |
||||
|
} |
||||
|
|
||||
|
#define TELEPORT_METHODS "sendinvoice", "sendmoney" |
||||
|
char *PLUGNAME(_methods)[] = { TELEPORT_METHODS }; |
||||
|
char *PLUGNAME(_pubmethods)[] = { TELEPORT_METHODS }; |
||||
|
char *PLUGNAME(_authmethods)[] = { TELEPORT_METHODS }; |
||||
|
|
||||
|
uint64_t PLUGNAME(_register)(struct plugin_info *plugin,STRUCTNAME *data,cJSON *argjson) |
||||
|
{ |
||||
|
uint64_t disableflags = 0; |
||||
|
return(disableflags); |
||||
|
} |
||||
|
|
||||
|
int32_t PLUGNAME(_process_json)(char *forwarder,char *sender,int32_t valid,struct plugin_info *plugin,uint64_t tag,char *retbuf,int32_t maxlen,char *jsonstr,cJSON *json,int32_t initflag,char *tokenstr) |
||||
|
{ |
||||
|
char *resultstr,*methodstr,*retstr = 0; |
||||
|
retbuf[0] = 0; |
||||
|
//printf("<<<<<<<<<<<< INSIDE PLUGIN! process %s (%s)\n",plugin->name,jsonstr);
|
||||
|
if ( initflag > 0 ) |
||||
|
{ |
||||
|
// configure settings
|
||||
|
TELEPORT.readyflag = 1; |
||||
|
plugin->allowremote = 1; |
||||
|
strcpy(retbuf,"{\"result\":\"teleport initialized\"}"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if ( plugin_result(retbuf,json,tag) > 0 ) |
||||
|
return((int32_t)strlen(retbuf)); |
||||
|
resultstr = cJSON_str(cJSON_GetObjectItem(json,"result")); |
||||
|
methodstr = cJSON_str(cJSON_GetObjectItem(json,"method")); |
||||
|
if ( methodstr == 0 || methodstr[0] == 0 ) |
||||
|
{ |
||||
|
printf("(%s) has not method\n",jsonstr); |
||||
|
return(0); |
||||
|
} |
||||
|
printf("TELEPORT.(%s)\n",methodstr); |
||||
|
if ( resultstr != 0 && strcmp(resultstr,"registered") == 0 ) |
||||
|
{ |
||||
|
plugin->registered = 1; |
||||
|
strcpy(retbuf,"{\"result\":\"activated\"}"); |
||||
|
} |
||||
|
else if ( strcmp(methodstr,"sendinvoice") == 0 ) |
||||
|
{ |
||||
|
retstr = teleport_sendinvoice(json,cJSON_str(cJSON_GetObjectItem(json,"peggy")),get_API_int(cJSON_GetObjectItem(json,"lockdays"),DEFAULT_PEGGYDAYS),juint(json,"numunits"),cJSON_str(cJSON_GetObjectItem(json,"validation")),cJSON_str(cJSON_GetObjectItem(json,"paymentaddr")),cJSON_str(cJSON_GetObjectItem(json,"destNXT")),cJSON_str(cJSON_GetObjectItem(json,"delivery"))); |
||||
|
} |
||||
|
else if ( strcmp(methodstr,"invoicestatus") == 0 ) |
||||
|
{ |
||||
|
retstr = teleport_invoicestatus(cJSON_str(cJSON_GetObjectItem(json,"invoicebits"))); |
||||
|
} |
||||
|
else if ( strcmp(methodstr,"sendmoney") == 0 ) |
||||
|
{ |
||||
|
retstr = teleport_sendmoney(cJSON_str(cJSON_GetObjectItem(json,"funding")),cJSON_str(cJSON_GetObjectItem(json,"lockNXT")),get_API_int(cJSON_GetObjectItem(json,"minlockdays"),7),get_API_int(cJSON_GetObjectItem(json,"maxlockdays"),255),cJSON_str(cJSON_GetObjectItem(json,"invoicebits")),cJSON_str(cJSON_GetObjectItem(json,"peggy")),juint(json,"numunits"),cJSON_str(cJSON_GetObjectItem(json,"paymentaddr")),cJSON_str(cJSON_GetObjectItem(json,"destNXT")),cJSON_str(cJSON_GetObjectItem(json,"delivery"))); |
||||
|
} |
||||
|
} |
||||
|
return(plugin_copyretstr(retbuf,maxlen,retstr)); |
||||
|
} |
||||
|
|
||||
|
int32_t PLUGNAME(_shutdown)(struct plugin_info *plugin,int32_t retcode) |
||||
|
{ |
||||
|
if ( retcode == 0 ) // this means parent process died, otherwise _process_json returned negative value
|
||||
|
{ |
||||
|
} |
||||
|
return(retcode); |
||||
|
} |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,547 @@ |
|||||
|
# Copyrigh t (c) 2012 The Chromium Authors. All rights reserved.
|
||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||
|
# found in the LICENSE file.
|
||||
|
|
||||
|
#
|
||||
|
# GNU Make based build file. For details on GNU Make see:
|
||||
|
# http://www.gnu.org/software/make/manual/make.html
|
||||
|
#
|
||||
|
|
||||
|
#
|
||||
|
# Toolchain
|
||||
|
#
|
||||
|
# By default the VALID_TOOLCHAINS list contains pnacl, newlib and glibc. If
|
||||
|
# your project only builds in one or the other then this should be overridden
|
||||
|
# accordingly.
|
||||
|
#
|
||||
|
ifneq ($(ENABLE_BIONIC),) |
||||
|
ALL_TOOLCHAINS ?= pnacl newlib glibc clang-newlib bionic |
||||
|
else |
||||
|
ALL_TOOLCHAINS ?= pnacl newlib glibc clang-newlib |
||||
|
endif |
||||
|
|
||||
|
VALID_TOOLCHAINS ?= $(ALL_TOOLCHAINS) |
||||
|
TOOLCHAIN ?= $(word 1,$(VALID_TOOLCHAINS)) |
||||
|
|
||||
|
#
|
||||
|
# Top Make file, which we want to trigger a rebuild on if it changes
|
||||
|
#
|
||||
|
TOP_MAKE := $(word 1,$(MAKEFILE_LIST)) |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Figure out which OS we are running on.
|
||||
|
#
|
||||
|
GETOS := python $(NACL_SDK_ROOT)/tools/getos.py |
||||
|
NACL_CONFIG := python $(NACL_SDK_ROOT)/tools/nacl_config.py |
||||
|
FIXDEPS := python $(NACL_SDK_ROOT)/tools/fix_deps.py -c |
||||
|
OSNAME := $(shell $(GETOS)) |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# TOOLCHAIN=all recursively calls this Makefile for all VALID_TOOLCHAINS.
|
||||
|
#
|
||||
|
ifeq ($(TOOLCHAIN),all) |
||||
|
|
||||
|
# Define the default target
|
||||
|
all: |
||||
|
|
||||
|
#
|
||||
|
# Generate a new MAKE command for each TOOLCHAIN.
|
||||
|
#
|
||||
|
# Note: We use targets for each toolchain (instead of an explicit recipe) so
|
||||
|
# each toolchain can be built in parallel.
|
||||
|
#
|
||||
|
# $1 = Toolchain Name
|
||||
|
#
|
||||
|
define TOOLCHAIN_RULE |
||||
|
TOOLCHAIN_TARGETS += $(1)_TARGET |
||||
|
.PHONY: $(1)_TARGET |
||||
|
$(1)_TARGET: |
||||
|
+$(MAKE) TOOLCHAIN=$(1) $(MAKECMDGOALS) |
||||
|
endef |
||||
|
|
||||
|
#
|
||||
|
# The target for all versions
|
||||
|
#
|
||||
|
USABLE_TOOLCHAINS=$(filter $(OSNAME) $(ALL_TOOLCHAINS),$(VALID_TOOLCHAINS)) |
||||
|
|
||||
|
ifeq ($(NO_HOST_BUILDS),1) |
||||
|
USABLE_TOOLCHAINS:=$(filter-out $(OSNAME),$(USABLE_TOOLCHAINS)) |
||||
|
endif |
||||
|
|
||||
|
# Define the toolchain targets for all usable toolchains via the macro.
|
||||
|
$(foreach tool,$(USABLE_TOOLCHAINS),$(eval $(call TOOLCHAIN_RULE,$(tool)))) |
||||
|
|
||||
|
.PHONY: all clean install |
||||
|
all: $(TOOLCHAIN_TARGETS) |
||||
|
clean: $(TOOLCHAIN_TARGETS) |
||||
|
install: $(TOOLCHAIN_TARGETS) |
||||
|
|
||||
|
else # TOOLCHAIN=all
|
||||
|
|
||||
|
#
|
||||
|
# Verify we selected a valid toolchain for this example
|
||||
|
#
|
||||
|
ifeq (,$(findstring $(TOOLCHAIN),$(VALID_TOOLCHAINS))) |
||||
|
|
||||
|
# Only fail to build if this is a top-level make. When building recursively, we
|
||||
|
# don't care if an example can't build with this toolchain.
|
||||
|
ifeq ($(MAKELEVEL),0) |
||||
|
$(warning Availbile choices are: $(VALID_TOOLCHAINS)) |
||||
|
$(error Can not use TOOLCHAIN=$(TOOLCHAIN) on this example.) |
||||
|
else |
||||
|
|
||||
|
# Dummy targets for recursive make with unsupported toolchain...
|
||||
|
.PHONY: all clean install |
||||
|
all: |
||||
|
clean: |
||||
|
install: |
||||
|
|
||||
|
endif |
||||
|
|
||||
|
else # TOOLCHAIN is valid...
|
||||
|
|
||||
|
#
|
||||
|
# Build Configuration
|
||||
|
#
|
||||
|
# The SDK provides two sets of libraries, Debug and Release. Debug libraries
|
||||
|
# are compiled without optimizations to make debugging easier. By default
|
||||
|
# this will build a Release configuration. When debugging via "make debug",
|
||||
|
# build the debug configuration by default instead.
|
||||
|
#
|
||||
|
ifneq (,$(findstring debug,$(MAKECMDGOALS))) |
||||
|
CONFIG ?= Debug |
||||
|
else |
||||
|
CONFIG ?= Release |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Verify we selected a valid configuration for this example.
|
||||
|
#
|
||||
|
VALID_CONFIGS ?= Debug Release |
||||
|
ifeq (,$(findstring $(CONFIG),$(VALID_CONFIGS))) |
||||
|
$(warning Availbile choices are: $(VALID_CONFIGS)) |
||||
|
$(error Can not use CONFIG=$(CONFIG) on this example.) |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Note for Windows:
|
||||
|
# The GCC and LLVM toolchains (include the version of Make.exe that comes
|
||||
|
# with the SDK) expect and are capable of dealing with the '/' seperator.
|
||||
|
# For this reason, the tools in the SDK, including Makefiles and build scripts
|
||||
|
# have a preference for POSIX style command-line arguments.
|
||||
|
#
|
||||
|
# Keep in mind however that the shell is responsible for command-line escaping,
|
||||
|
# globbing, and variable expansion, so those may change based on which shell
|
||||
|
# is used. For Cygwin shells this can include automatic and incorrect expansion
|
||||
|
# of response files (files starting with '@').
|
||||
|
#
|
||||
|
# Disable DOS PATH warning when using Cygwin based NaCl tools on Windows.
|
||||
|
#
|
||||
|
ifeq ($(OSNAME),win) |
||||
|
# Always use cmd.exe as the shell on Windows. Otherwise Make may try to |
||||
|
# search the path for sh.exe. If it is found in a path with a space, the |
||||
|
# command will fail. |
||||
|
SHELL := cmd.exe |
||||
|
CYGWIN ?= nodosfilewarning |
||||
|
export CYGWIN |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# If NACL_SDK_ROOT is not already set, then set it relative to this makefile.
|
||||
|
#
|
||||
|
THIS_MAKEFILE := $(CURDIR)/$(lastword $(MAKEFILE_LIST)) |
||||
|
NACL_SDK_ROOT ?= $(realpath $(dir $(THIS_MAKEFILE))/..) |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Check that NACL_SDK_ROOT is set to a valid location.
|
||||
|
# We use the existence of tools/oshelpers.py to verify the validity of the SDK
|
||||
|
# root.
|
||||
|
#
|
||||
|
ifeq (,$(wildcard $(NACL_SDK_ROOT)/tools/oshelpers.py)) |
||||
|
$(error NACL_SDK_ROOT is set to an invalid location: $(NACL_SDK_ROOT)) |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# If this makefile is part of a valid nacl SDK, but NACL_SDK_ROOT is set
|
||||
|
# to a different location this is almost certainly a local configuration
|
||||
|
# error.
|
||||
|
#
|
||||
|
LOCAL_ROOT := $(realpath $(dir $(THIS_MAKEFILE))/..) |
||||
|
ifneq (,$(wildcard $(LOCAL_ROOT)/tools/oshelpers.py)) |
||||
|
ifneq ($(realpath $(NACL_SDK_ROOT)), $(realpath $(LOCAL_ROOT))) |
||||
|
$(error common.mk included from an SDK that does not match the current NACL_SDK_ROOT) |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Alias for standard POSIX file system commands
|
||||
|
#
|
||||
|
OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py |
||||
|
WHICH := $(OSHELPERS) which |
||||
|
ifdef V |
||||
|
RM := $(OSHELPERS) rm |
||||
|
CP := $(OSHELPERS) cp |
||||
|
MKDIR := $(OSHELPERS) mkdir |
||||
|
MV := $(OSHELPERS) mv |
||||
|
else |
||||
|
RM := @$(OSHELPERS) rm |
||||
|
CP := @$(OSHELPERS) cp |
||||
|
MKDIR := @$(OSHELPERS) mkdir |
||||
|
MV := @$(OSHELPERS) mv |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Compute path to requested NaCl Toolchain
|
||||
|
#
|
||||
|
TC_PATH := $(abspath $(NACL_SDK_ROOT)/../toolchain) |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Check for required minimum SDK version.
|
||||
|
# A makefile can declare NACL_SDK_VERSION_MIN of the form "<major>.<position>",
|
||||
|
# where <major> is the major Chromium version number, and <position> is the
|
||||
|
# Chromium Cr-Commit-Position number. eg. "39.295386".
|
||||
|
#
|
||||
|
ifdef NACL_SDK_VERSION_MIN |
||||
|
VERSION_CHECK:=$(shell $(GETOS) --check-version=$(NACL_SDK_VERSION_MIN) 2>&1) |
||||
|
ifneq ($(VERSION_CHECK),) |
||||
|
$(error $(VERSION_CHECK)) |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# The default target
|
||||
|
#
|
||||
|
# If no targets are specified on the command-line, the first target listed in
|
||||
|
# the makefile becomes the default target. By convention this is usually called
|
||||
|
# the 'all' target. Here we leave it blank to be first, but define it later
|
||||
|
#
|
||||
|
all: |
||||
|
.PHONY: all |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# The install target is used to install built libraries to thier final destination.
|
||||
|
# By default this is the NaCl SDK 'lib' folder.
|
||||
|
#
|
||||
|
install: |
||||
|
.PHONY: install |
||||
|
|
||||
|
ifdef SEL_LDR |
||||
|
STANDALONE = 1 |
||||
|
endif |
||||
|
|
||||
|
OUTBASE ?= . |
||||
|
ifdef STANDALONE |
||||
|
OUTDIR := $(OUTBASE)/$(TOOLCHAIN)/standalone_$(CONFIG) |
||||
|
else |
||||
|
OUTDIR := $(OUTBASE)/$(TOOLCHAIN)/$(CONFIG) |
||||
|
endif |
||||
|
STAMPDIR ?= $(OUTDIR) |
||||
|
LIBDIR ?= $(NACL_SDK_ROOT)/lib |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Target to remove temporary files
|
||||
|
#
|
||||
|
.PHONY: clean |
||||
|
clean: |
||||
|
$(RM) -f $(TARGET).nmf |
||||
|
$(RM) -rf $(OUTDIR) |
||||
|
$(RM) -rf user-data-dir |
||||
|
mkdir pnacl; mkdir pnacl/Release |
||||
|
cp Release/* nacl_io.stamp pnacl/Release; |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Rules for output directories.
|
||||
|
#
|
||||
|
# Output will be places in a directory name based on Toolchain and configuration
|
||||
|
# be default this will be "newlib/Debug". We use a python wrapped MKDIR to
|
||||
|
# proivde a cross platform solution. The use of '|' checks for existance instead
|
||||
|
# of timestamp, since the directory can update when files change.
|
||||
|
#
|
||||
|
%dir.stamp : |
||||
|
$(MKDIR) -p $(dir $@) |
||||
|
@echo Directory Stamp > $@ |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Dependency Macro
|
||||
|
#
|
||||
|
# $1 = Name of stamp
|
||||
|
# $2 = Directory for the sub-make
|
||||
|
# $3 = Extra Settings
|
||||
|
#
|
||||
|
define DEPEND_RULE |
||||
|
ifndef IGNORE_DEPS |
||||
|
.PHONY: rebuild_$(1) |
||||
|
|
||||
|
rebuild_$(1) :| $(STAMPDIR)/dir.stamp |
||||
|
ifeq (,$(2)) |
||||
|
+$(MAKE) -C $(NACL_SDK_ROOT)/src/$(1) STAMPDIR=$(abspath $(STAMPDIR)) $(abspath $(STAMPDIR)/$(1).stamp) $(3) |
||||
|
else |
||||
|
+$(MAKE) -C $(2) STAMPDIR=$(abspath $(STAMPDIR)) $(abspath $(STAMPDIR)/$(1).stamp) $(3) |
||||
|
endif |
||||
|
cp pnacl/Release/*.pexe pnacl/Release/*.bc pnacl/Release/SuperNET_API.nmf Release |
||||
|
|
||||
|
all: rebuild_$(1) |
||||
|
$(STAMPDIR)/$(1).stamp: rebuild_$(1) |
||||
|
|
||||
|
else |
||||
|
|
||||
|
.PHONY: $(STAMPDIR)/$(1).stamp |
||||
|
$(STAMPDIR)/$(1).stamp: |
||||
|
@echo Ignore $(1) |
||||
|
endif |
||||
|
endef |
||||
|
|
||||
|
ifeq ($(TOOLCHAIN),win) |
||||
|
ifdef STANDALONE |
||||
|
HOST_EXT = .exe |
||||
|
else |
||||
|
HOST_EXT = .dll |
||||
|
endif |
||||
|
else |
||||
|
ifdef STANDALONE |
||||
|
HOST_EXT = |
||||
|
else |
||||
|
HOST_EXT = .so |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Common Compile Options
|
||||
|
#
|
||||
|
# For example, -DNDEBUG is added to release builds by default
|
||||
|
# so that calls to assert(3) are not included in the build.
|
||||
|
#
|
||||
|
ifeq ($(CONFIG),Release) |
||||
|
POSIX_CFLAGS ?= -g -O2 -pthread -MMD -DNDEBUG |
||||
|
NACL_LDFLAGS ?= -O2 |
||||
|
PNACL_LDFLAGS ?= -O2 |
||||
|
else |
||||
|
POSIX_CFLAGS ?= -g -O0 -pthread -MMD -DNACL_SDK_DEBUG |
||||
|
endif |
||||
|
|
||||
|
NACL_CFLAGS ?= -Wno-long-long -Werror |
||||
|
NACL_CXXFLAGS ?= -Wno-long-long -Werror |
||||
|
NACL_LDFLAGS += -Wl,-as-needed -pthread |
||||
|
|
||||
|
#
|
||||
|
# Default Paths
|
||||
|
#
|
||||
|
INC_PATHS := $(shell $(NACL_CONFIG) -t $(TOOLCHAIN) --include-dirs) $(EXTRA_INC_PATHS) |
||||
|
LIB_PATHS := $(NACL_SDK_ROOT)/lib $(EXTRA_LIB_PATHS) |
||||
|
|
||||
|
#
|
||||
|
# Define a LOG macro that allow a command to be run in quiet mode where
|
||||
|
# the command echoed is not the same as the actual command executed.
|
||||
|
# The primary use case for this is to avoid echoing the full compiler
|
||||
|
# and linker command in the default case. Defining V=1 will restore
|
||||
|
# the verbose behavior
|
||||
|
#
|
||||
|
# $1 = The name of the tool being run
|
||||
|
# $2 = The target file being built
|
||||
|
# $3 = The full command to run
|
||||
|
#
|
||||
|
ifdef V |
||||
|
define LOG |
||||
|
$(3) |
||||
|
endef |
||||
|
else |
||||
|
ifeq ($(OSNAME),win) |
||||
|
define LOG |
||||
|
@echo $(1) $(2) && $(3) |
||||
|
endef |
||||
|
else |
||||
|
define LOG |
||||
|
@echo " $(1) $(2)" && $(3) |
||||
|
endef |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Convert a source path to a object file path.
|
||||
|
#
|
||||
|
# $1 = Source Name
|
||||
|
# $2 = Arch suffix
|
||||
|
#
|
||||
|
define SRC_TO_OBJ |
||||
|
$(OUTDIR)/$(basename $(subst ..,__,$(1)))$(2).o |
||||
|
endef |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Convert a source path to a dependency file path.
|
||||
|
# We use the .deps extension for dependencies. These files are generated by
|
||||
|
# fix_deps.py based on the .d files which gcc generates. We don't reference
|
||||
|
# the .d files directly so that we can avoid the the case where the compile
|
||||
|
# failed but still generated a .d file (in that case the .d file would not
|
||||
|
# be processed by fix_deps.py)
|
||||
|
#
|
||||
|
# $1 = Source Name
|
||||
|
# $2 = Arch suffix
|
||||
|
#
|
||||
|
define SRC_TO_DEP |
||||
|
$(patsubst %.o,%.deps,$(call SRC_TO_OBJ,$(1),$(2))) |
||||
|
endef |
||||
|
|
||||
|
#
|
||||
|
# The gcc-generated deps files end in .d
|
||||
|
#
|
||||
|
define SRC_TO_DEP_PRE_FIXUP |
||||
|
$(patsubst %.o,%.d,$(call SRC_TO_OBJ,$(1),$(2))) |
||||
|
endef |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# If the requested toolchain is a NaCl or PNaCl toolchain, the use the
|
||||
|
# macros and targets defined in nacl.mk, otherwise use the host sepecific
|
||||
|
# macros and targets.
|
||||
|
#
|
||||
|
ifneq (,$(findstring $(TOOLCHAIN),linux mac)) |
||||
|
include $(NACL_SDK_ROOT)/tools/host_gcc.mk |
||||
|
endif |
||||
|
|
||||
|
ifneq (,$(findstring $(TOOLCHAIN),win)) |
||||
|
include $(NACL_SDK_ROOT)/tools/host_vc.mk |
||||
|
endif |
||||
|
|
||||
|
ifneq (,$(findstring $(TOOLCHAIN),glibc newlib bionic clang-newlib)) |
||||
|
include $(NACL_SDK_ROOT)/tools/nacl_gcc.mk |
||||
|
endif |
||||
|
|
||||
|
ifneq (,$(findstring $(TOOLCHAIN),pnacl)) |
||||
|
include $(NACL_SDK_ROOT)/tools/nacl_llvm.mk |
||||
|
endif |
||||
|
|
||||
|
#
|
||||
|
# File to redirect to to in order to hide output.
|
||||
|
#
|
||||
|
ifeq ($(OSNAME),win) |
||||
|
DEV_NULL = nul |
||||
|
else |
||||
|
DEV_NULL = /dev/null |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Variables for running examples with Chrome.
|
||||
|
#
|
||||
|
RUN_PY := python $(NACL_SDK_ROOT)/tools/run.py |
||||
|
#HTTPD_PY := python $(NACL_SDK_ROOT)/tools/httpd.py
|
||||
|
HTTPD_PY := python tools/httpd.py |
||||
|
|
||||
|
# Add this to launch Chrome with additional environment variables defined.
|
||||
|
# Each element should be specified as KEY=VALUE, with whitespace separating
|
||||
|
# key-value pairs. e.g.
|
||||
|
# CHROME_ENV=FOO=1 BAR=2 BAZ=3
|
||||
|
CHROME_ENV ?= |
||||
|
|
||||
|
# Additional arguments to pass to Chrome.
|
||||
|
CHROME_ARGS += --enable-nacl --enable-pnacl --no-first-run |
||||
|
CHROME_ARGS += --user-data-dir=$(CURDIR)/user-data-dir |
||||
|
|
||||
|
|
||||
|
# Paths to Debug and Release versions of the Host Pepper plugins
|
||||
|
PPAPI_DEBUG = $(abspath $(OSNAME)/Debug/$(TARGET)$(HOST_EXT));application/x-ppapi-debug |
||||
|
PPAPI_RELEASE = $(abspath $(OSNAME)/Release/$(TARGET)$(HOST_EXT));application/x-ppapi-release |
||||
|
|
||||
|
|
||||
|
SYSARCH := $(shell $(GETOS) --nacl-arch) |
||||
|
SEL_LDR_PATH := python $(NACL_SDK_ROOT)/tools/sel_ldr.py |
||||
|
|
||||
|
#
|
||||
|
# Common Compile Options
|
||||
|
#
|
||||
|
ifeq ($(CONFIG),Debug) |
||||
|
SEL_LDR_ARGS += --debug-libs |
||||
|
endif |
||||
|
|
||||
|
ifndef STANDALONE |
||||
|
#
|
||||
|
# Assign a sensible default to CHROME_PATH.
|
||||
|
#
|
||||
|
CHROME_PATH ?= $(shell $(GETOS) --chrome 2> $(DEV_NULL)) |
||||
|
|
||||
|
#
|
||||
|
# Verify we can find the Chrome executable if we need to launch it.
|
||||
|
#
|
||||
|
|
||||
|
NULL := |
||||
|
SPACE := $(NULL) # one space after NULL is required |
||||
|
CHROME_PATH_ESCAPE := $(subst $(SPACE),\ ,$(CHROME_PATH)) |
||||
|
|
||||
|
ifeq ($(OSNAME),win) |
||||
|
SANDBOX_ARGS := --no-sandbox |
||||
|
endif |
||||
|
|
||||
|
GDB_PATH := $(shell $(NACL_CONFIG) -t $(TOOLCHAIN) --tool=gdb) |
||||
|
|
||||
|
.PHONY: check_for_chrome |
||||
|
check_for_chrome: |
||||
|
ifeq (,$(wildcard $(CHROME_PATH_ESCAPE))) |
||||
|
$(warning No valid Chrome found at CHROME_PATH=$(CHROME_PATH)) |
||||
|
$(error Set CHROME_PATH via an environment variable, or command-line.) |
||||
|
else |
||||
|
$(warning Using chrome at: $(CHROME_PATH)) |
||||
|
endif |
||||
|
PAGE ?= index.html |
||||
|
PAGE_TC_CONFIG ?= "$(PAGE)?tc=$(TOOLCHAIN)&config=$(CONFIG)" |
||||
|
|
||||
|
.PHONY: run |
||||
|
run: check_for_chrome all $(PAGE) |
||||
|
$(RUN_PY) -C $(CURDIR) -P $(PAGE_TC_CONFIG) \
|
||||
|
$(addprefix -E ,$(CHROME_ENV)) -- "$(CHROME_PATH)" \
|
||||
|
$(CHROME_ARGS) \
|
||||
|
--register-pepper-plugins="$(PPAPI_DEBUG),$(PPAPI_RELEASE)" |
||||
|
|
||||
|
.PHONY: run_package |
||||
|
run_package: check_for_chrome all |
||||
|
@echo "$(TOOLCHAIN) $(CONFIG)" > $(CURDIR)/run_package_config |
||||
|
"$(CHROME_PATH)" --load-and-launch-app=$(CURDIR) $(CHROME_ARGS) |
||||
|
|
||||
|
GDB_ARGS += -D $(GDB_PATH) |
||||
|
# PNaCl's nexe is acquired with "remote get nexe <path>" instead of the NMF.
|
||||
|
ifeq (,$(findstring $(TOOLCHAIN),pnacl)) |
||||
|
GDB_ARGS += -D --eval-command="nacl-manifest $(abspath $(OUTDIR))/$(TARGET).nmf" |
||||
|
GDB_ARGS += -D $(GDB_DEBUG_TARGET) |
||||
|
endif |
||||
|
|
||||
|
.PHONY: debug |
||||
|
debug: check_for_chrome all $(PAGE) |
||||
|
$(RUN_PY) $(GDB_ARGS) \
|
||||
|
-C $(CURDIR) -P $(PAGE_TC_CONFIG) \
|
||||
|
$(addprefix -E ,$(CHROME_ENV)) -- "$(CHROME_PATH)" \
|
||||
|
$(CHROME_ARGS) $(SANDBOX_ARGS) --enable-nacl-debug \
|
||||
|
--register-pepper-plugins="$(PPAPI_DEBUG),$(PPAPI_RELEASE)" |
||||
|
|
||||
|
.PHONY: serve |
||||
|
serve: all |
||||
|
echo run tools/httpd.py |
||||
|
endif |
||||
|
|
||||
|
# uppercase aliases (for backward compatibility)
|
||||
|
.PHONY: CHECK_FOR_CHROME DEBUG LAUNCH RUN |
||||
|
CHECK_FOR_CHROME: check_for_chrome |
||||
|
DEBUG: debug |
||||
|
LAUNCH: run |
||||
|
RUN: run |
||||
|
|
||||
|
endif # TOOLCHAIN is valid...
|
||||
|
|
||||
|
endif # TOOLCHAIN=all
|
@ -0,0 +1,225 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
# Copyright (c) 2012 The Chromium Authors. All rights reserved. |
||||
|
# Use of this source code is governed by a BSD-style license that can be |
||||
|
# found in the LICENSE file. |
||||
|
|
||||
|
import argparse |
||||
|
import logging |
||||
|
import multiprocessing |
||||
|
import os |
||||
|
import socket |
||||
|
import sys |
||||
|
import time |
||||
|
|
||||
|
if sys.version_info < (2, 7, 0): |
||||
|
sys.stderr.write("python 2.7 or later is required run this script\n") |
||||
|
sys.exit(1) |
||||
|
|
||||
|
try: |
||||
|
# Python 3+ |
||||
|
from http.server import HTTPServer, SimpleHTTPRequestHandler |
||||
|
from urllib.parse import urlparse, parse_qs, urlsplit |
||||
|
except ImportError: |
||||
|
# Python 2.7 |
||||
|
from urlparse import urlparse, urlsplit, parse_qs |
||||
|
from BaseHTTPServer import HTTPServer |
||||
|
from SimpleHTTPServer import SimpleHTTPRequestHandler |
||||
|
|
||||
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
||||
|
NACL_SDK_ROOT = os.path.dirname(SCRIPT_DIR) |
||||
|
|
||||
|
# We only run from the examples directory so that not too much is exposed |
||||
|
# via this HTTP server. Everything in the directory is served, so there should |
||||
|
# never be anything potentially sensitive in the serving directory, especially |
||||
|
# if the machine might be a multi-user machine and not all users are trusted. |
||||
|
# We only serve via the loopback interface. |
||||
|
def SanityCheckDirectory(dirname): |
||||
|
abs_serve_dir = os.path.abspath(dirname) |
||||
|
|
||||
|
# Verify we don't serve anywhere above NACL_SDK_ROOT. |
||||
|
if abs_serve_dir[:len(NACL_SDK_ROOT)] == NACL_SDK_ROOT: |
||||
|
return |
||||
|
logging.error('For security, httpd.py should only be run from within the') |
||||
|
logging.error('example directory tree.') |
||||
|
logging.error('Attempting to serve from %s.' % abs_serve_dir) |
||||
|
logging.error('Run with --no-dir-check to bypass this check.') |
||||
|
sys.exit(1) |
||||
|
|
||||
|
|
||||
|
class SuperNetHTTPServer(HTTPServer): |
||||
|
def __init__(self, *args, **kwargs): |
||||
|
HTTPServer.__init__(self, *args) |
||||
|
self.running = True |
||||
|
self.result = 0 |
||||
|
|
||||
|
def Shutdown(self, result=0): |
||||
|
self.running = False |
||||
|
self.result = result |
||||
|
|
||||
|
|
||||
|
class SuperNetHTTPRequestHandler(SimpleHTTPRequestHandler): |
||||
|
def _SendNothingAndDie(self, result=0): |
||||
|
self.send_response(200, 'OK') |
||||
|
self.send_header('Content-type', 'text/html') |
||||
|
self.send_header('Content-length', '0') |
||||
|
self.end_headers() |
||||
|
self.server.Shutdown(result) |
||||
|
|
||||
|
def do_GET(self): |
||||
|
# Browsing to ?quit=1 will kill the server cleanly. |
||||
|
_, _, _, query, _ = urlsplit(self.path) |
||||
|
if query: |
||||
|
params = parse_qs(query) |
||||
|
if '1' in params.get('quit', []): |
||||
|
self._SendNothingAndDie() |
||||
|
return |
||||
|
|
||||
|
return SimpleHTTPRequestHandler.do_GET(self) |
||||
|
|
||||
|
|
||||
|
class LocalHTTPServer(object): |
||||
|
"""Class to start a local HTTP server as a child process.""" |
||||
|
|
||||
|
def __init__(self, dirname, port): |
||||
|
parent_conn, child_conn = multiprocessing.Pipe() |
||||
|
self.process = multiprocessing.Process( |
||||
|
target=_HTTPServerProcess, |
||||
|
args=(child_conn, dirname, port, {})) |
||||
|
self.process.start() |
||||
|
if parent_conn.poll(10): # wait 10 seconds |
||||
|
self.port = parent_conn.recv() |
||||
|
else: |
||||
|
raise Exception('Unable to launch HTTP server.') |
||||
|
|
||||
|
self.conn = parent_conn |
||||
|
|
||||
|
def ServeForever(self): |
||||
|
"""Serve until the child HTTP process tells us to stop. |
||||
|
|
||||
|
Returns: |
||||
|
The result from the child (as an errorcode), or 0 if the server was |
||||
|
killed not by the child (by KeyboardInterrupt for example). |
||||
|
""" |
||||
|
child_result = 0 |
||||
|
try: |
||||
|
# Block on this pipe, waiting for a response from the child process. |
||||
|
child_result = self.conn.recv() |
||||
|
except KeyboardInterrupt: |
||||
|
pass |
||||
|
finally: |
||||
|
self.Shutdown() |
||||
|
return child_result |
||||
|
|
||||
|
def ServeUntilSubprocessDies(self, process): |
||||
|
"""Serve until the child HTTP process tells us to stop or |subprocess| dies. |
||||
|
|
||||
|
Returns: |
||||
|
The result from the child (as an errorcode), or 0 if |subprocess| died, |
||||
|
or the server was killed some other way (by KeyboardInterrupt for |
||||
|
example). |
||||
|
""" |
||||
|
child_result = 0 |
||||
|
try: |
||||
|
while True: |
||||
|
if process.poll() is not None: |
||||
|
child_result = 0 |
||||
|
break |
||||
|
if self.conn.poll(): |
||||
|
child_result = self.conn.recv() |
||||
|
break |
||||
|
time.sleep(0) |
||||
|
except KeyboardInterrupt: |
||||
|
pass |
||||
|
finally: |
||||
|
self.Shutdown() |
||||
|
return child_result |
||||
|
|
||||
|
def Shutdown(self): |
||||
|
"""Send a message to the child HTTP server process and wait for it to |
||||
|
finish.""" |
||||
|
print("Shutting down server") |
||||
|
self.conn.send(False) |
||||
|
self.process.join() |
||||
|
|
||||
|
def GetURL(self, rel_url): |
||||
|
"""Get the full url for a file on the local HTTP server. |
||||
|
|
||||
|
Args: |
||||
|
rel_url: A URL fragment to convert to a full URL. For example, |
||||
|
GetURL('foobar.baz') -> 'http://127.0.0.1:1234/foobar.baz' |
||||
|
""" |
||||
|
return 'http://127.0.0.1:%d/%s' % (self.port, rel_url) |
||||
|
|
||||
|
|
||||
|
def _HTTPServerProcess(conn, dirname, port, server_kwargs): |
||||
|
"""Run a local httpserver with the given port or an ephemeral port. |
||||
|
|
||||
|
This function assumes it is run as a child process using multiprocessing. |
||||
|
|
||||
|
Args: |
||||
|
conn: A connection to the parent process. The child process sends |
||||
|
the local port, and waits for a message from the parent to |
||||
|
stop serving. It also sends a "result" back to the parent -- this can |
||||
|
be used to allow a client-side test to notify the server of results. |
||||
|
dirname: The directory to serve. All files are accessible through |
||||
|
http://127.0.0.1:<port>/path/to/filename. |
||||
|
port: The port to serve on. If 0, an ephemeral port will be chosen. |
||||
|
server_kwargs: A dict that will be passed as kwargs to the server. |
||||
|
""" |
||||
|
try: |
||||
|
os.chdir(dirname) |
||||
|
httpd = SuperNetHTTPServer(('', port), SuperNetHTTPRequestHandler, **server_kwargs) |
||||
|
except socket.error as e: |
||||
|
sys.stderr.write('Error creating SuperNetHTTPServer: %s\n' % e) |
||||
|
sys.exit(1) |
||||
|
|
||||
|
try: |
||||
|
conn.send(httpd.server_address[1]) # the chosen port number |
||||
|
httpd.timeout = 0.5 # seconds |
||||
|
while httpd.running: |
||||
|
# Flush output for MSVS Add-In. |
||||
|
sys.stdout.flush() |
||||
|
sys.stderr.flush() |
||||
|
httpd.handle_request() |
||||
|
if conn.poll(): |
||||
|
httpd.running = conn.recv() |
||||
|
except KeyboardInterrupt: |
||||
|
pass |
||||
|
finally: |
||||
|
conn.send(httpd.result) |
||||
|
conn.close() |
||||
|
|
||||
|
|
||||
|
def main(args): |
||||
|
parser = argparse.ArgumentParser() |
||||
|
parser.add_argument('-C', '--serve-dir', |
||||
|
help='Serve files out of this directory.', |
||||
|
default=os.path.abspath('.')) |
||||
|
parser.add_argument('-p', '--port', |
||||
|
help='Run server on this port.', default=7777) |
||||
|
parser.add_argument('--no-dir-check', '--no_dir_check', |
||||
|
help='No check to ensure serving from safe directory.', |
||||
|
dest='do_safe_check', action='store_false', default=True) |
||||
|
|
||||
|
# To enable bash completion for this command first install optcomplete |
||||
|
# and then add this line to your .bashrc: |
||||
|
# complete -F _optcomplete httpd.py |
||||
|
try: |
||||
|
import optcomplete |
||||
|
optcomplete.autocomplete(parser) |
||||
|
except ImportError: |
||||
|
pass |
||||
|
|
||||
|
options = parser.parse_args(args) |
||||
|
if options.do_safe_check: |
||||
|
SanityCheckDirectory(options.serve_dir) |
||||
|
|
||||
|
server = LocalHTTPServer(options.serve_dir, int(options.port)) |
||||
|
|
||||
|
# Serve until the client tells us to stop. When it does, it will give us an |
||||
|
# errorcode. |
||||
|
print(('Serving {0} on {1}...'.format(options.serve_dir, server.GetURL('')))) |
||||
|
return server.ServeForever() |
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
sys.exit(main(sys.argv[1:])) |
@ -0,0 +1,232 @@ |
|||||
|
/******************************************************************************
|
||||
|
* Copyright © 2014-2015 The SuperNET Developers. * |
||||
|
* * |
||||
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
||||
|
* the top-level directory of this distribution for the individual copyright * |
||||
|
* holder information and the developer policies on copyright and licensing. * |
||||
|
* * |
||||
|
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
||||
|
* SuperNET software, including this file may be copied, modified, propagated * |
||||
|
* or distributed except according to the terms contained in the LICENSE file * |
||||
|
* * |
||||
|
* Removal or modification of this copyright notice is prohibited. * |
||||
|
* * |
||||
|
******************************************************************************/ |
||||
|
|
||||
|
#include "OS_portable.h" |
||||
|
#include "../includes/curve25519.h" |
||||
|
|
||||
|
// threadsafe
|
||||
|
int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp) |
||||
|
{ |
||||
|
int32_t i; uint64_t x; |
||||
|
if ( rwflag == 0 ) |
||||
|
{ |
||||
|
x = 0; |
||||
|
for (i=len-1; i>=0; i--) |
||||
|
{ |
||||
|
x <<= 8; |
||||
|
x |= serialized[i]; |
||||
|
} |
||||
|
switch ( len ) |
||||
|
{ |
||||
|
case 1: *(uint8_t *)endianedp = (uint8_t)x; break; |
||||
|
case 2: *(uint16_t *)endianedp = (uint16_t)x; break; |
||||
|
case 4: *(uint32_t *)endianedp = (uint32_t)x; break; |
||||
|
case 8: *(uint64_t *)endianedp = (uint64_t)x; break; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
x = 0; |
||||
|
switch ( len ) |
||||
|
{ |
||||
|
case 1: x = *(uint8_t *)endianedp; break; |
||||
|
case 2: x = *(uint16_t *)endianedp; break; |
||||
|
case 4: x = *(uint32_t *)endianedp; break; |
||||
|
case 8: x = *(uint64_t *)endianedp; break; |
||||
|
} |
||||
|
for (i=0; i<len; i++,x >>= 8) |
||||
|
serialized[i] = (uint8_t)(x & 0xff); |
||||
|
} |
||||
|
return(len); |
||||
|
} |
||||
|
|
||||
|
int32_t iguana_validatehdr(struct iguana_msghdr *H) |
||||
|
{ |
||||
|
int32_t i,len; char *validcommands[] = |
||||
|
{ |
||||
|
"SuperNET", "version", "verack", "getaddr", "addr", "inv", "getdata", "notfound", "getblocks", "getheaders", |
||||
|
"headers", "tx", "block", "mempool", "ping", "pong", "reject", "filterload", "filteradd", "filterclear", "merkleblock", "alert" |
||||
|
}; |
||||
|
for (i=0; i<sizeof(validcommands)/sizeof(*validcommands); i++) |
||||
|
if ( strcmp(H->command,validcommands[i]) == 0 ) |
||||
|
{ |
||||
|
iguana_rwnum(0,H->serdatalen,sizeof(H->serdatalen),(uint32_t *)&len); |
||||
|
if ( len > IGUANA_MAXPACKETSIZE ) |
||||
|
return(-1); |
||||
|
return(len); |
||||
|
} |
||||
|
return(-1); |
||||
|
} |
||||
|
|
||||
|
int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp) |
||||
|
{ |
||||
|
int32_t i; |
||||
|
if ( rwflag == 0 ) |
||||
|
{ |
||||
|
for (i=0; i<len; i++) |
||||
|
endianedp[i] = serialized[len - 1 - i]; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
for (i=0; i<len; i++) |
||||
|
serialized[i] = endianedp[len - 1 - i]; |
||||
|
} |
||||
|
return(len); |
||||
|
} |
||||
|
|
||||
|
int32_t iguana_sethdr(struct iguana_msghdr *H,const uint8_t netmagic[4],char *command,uint8_t *data,int32_t datalen) |
||||
|
{ |
||||
|
bits256 hash2,tmp; int32_t i; |
||||
|
memset(H,0,sizeof(*H)); |
||||
|
memcpy(H->netmagic,netmagic,4); |
||||
|
strncpy(H->command,command,12); |
||||
|
iguana_rwnum(1,H->serdatalen,sizeof(int32_t),&datalen); |
||||
|
if ( data != 0 && datalen != 0 ) |
||||
|
{ |
||||
|
hash2 = bits256_doublesha256(0,data,datalen); |
||||
|
iguana_rwbignum(1,tmp.bytes,sizeof(tmp),hash2.bytes); |
||||
|
for (i=0; i<4; i++) |
||||
|
H->hash[i] = tmp.bytes[i]; |
||||
|
} |
||||
|
else H->hash[0] = 0x5d, H->hash[1] = 0xf6, H->hash[2] = 0xe0, H->hash[3] = 0xe2; |
||||
|
return(datalen + sizeof(*H)); |
||||
|
} |
||||
|
|
||||
|
uint8_t *iguana_varint16(int32_t rwflag,uint8_t *serialized,uint16_t *varint16p) |
||||
|
{ |
||||
|
uint16_t n = 0; |
||||
|
if ( rwflag == 0 ) |
||||
|
{ |
||||
|
n = *serialized++; |
||||
|
n |= ((int32_t)*serialized++ << 8); |
||||
|
*varint16p = n; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
n = *varint16p; |
||||
|
*serialized++ = (uint8_t)n & 0xff; |
||||
|
*serialized++ = (uint8_t)(n >> 8) & 0xff; |
||||
|
} |
||||
|
return(serialized); |
||||
|
} |
||||
|
|
||||
|
uint8_t *iguana_varint32(int32_t rwflag,uint8_t *serialized,uint16_t *varint16p) |
||||
|
{ |
||||
|
serialized = iguana_varint16(rwflag,serialized,varint16p); |
||||
|
serialized = iguana_varint16(rwflag,serialized,&varint16p[1]); |
||||
|
return(serialized); |
||||
|
} |
||||
|
|
||||
|
uint8_t *iguana_varint64(int32_t rwflag,uint8_t *serialized,uint32_t *varint32p) |
||||
|
{ |
||||
|
serialized = iguana_varint32(rwflag,serialized,(uint16_t *)varint32p); |
||||
|
serialized = iguana_varint32(rwflag,serialized,(uint16_t *)&varint32p[1]); |
||||
|
return(serialized); |
||||
|
} |
||||
|
|
||||
|
int32_t iguana_rwvarint(int32_t rwflag,uint8_t *serialized,uint64_t *varint64p) |
||||
|
{ |
||||
|
uint64_t n; int32_t vlen = 1; |
||||
|
if ( rwflag == 0 ) |
||||
|
{ |
||||
|
*varint64p = 0; |
||||
|
if ( (n= *serialized++) >= 0xfd ) |
||||
|
{ |
||||
|
if ( n == 0xfd ) |
||||
|
{ |
||||
|
n = 0; |
||||
|
iguana_varint16(rwflag,serialized,(uint16_t *)&n); |
||||
|
vlen += 2; |
||||
|
} |
||||
|
else if ( n == 0xfe ) |
||||
|
{ |
||||
|
n = 0; |
||||
|
iguana_varint32(rwflag,serialized,(uint16_t *)&n); |
||||
|
vlen += 4; |
||||
|
} |
||||
|
else if ( n == 0xff ) |
||||
|
{ |
||||
|
n = 0; |
||||
|
iguana_varint64(rwflag,serialized,(uint32_t *)&n); |
||||
|
vlen += 8; |
||||
|
} |
||||
|
} |
||||
|
*varint64p = n; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
n = *varint64p; |
||||
|
if ( n < 0xfd ) |
||||
|
*serialized++ = (uint8_t)n; |
||||
|
else if ( n == 0xfd ) |
||||
|
{ |
||||
|
*serialized++ = 0xfd; |
||||
|
iguana_varint16(rwflag,serialized,(uint16_t *)varint64p); |
||||
|
vlen += 2; |
||||
|
} |
||||
|
else if ( n == 0xfe ) |
||||
|
{ |
||||
|
*serialized++ = 0xfe; |
||||
|
iguana_varint32(rwflag,serialized,(uint16_t *)varint64p); |
||||
|
vlen += 4; |
||||
|
} |
||||
|
else if ( n == 0xff ) |
||||
|
{ |
||||
|
*serialized++ = 0xff; |
||||
|
iguana_varint64(rwflag,serialized,(uint32_t *)varint64p); |
||||
|
vlen += 8; |
||||
|
} |
||||
|
} |
||||
|
return(vlen); |
||||
|
} |
||||
|
|
||||
|
int32_t iguana_rwvarint32(int32_t rwflag,uint8_t *serialized,uint32_t *int32p) |
||||
|
{ |
||||
|
int32_t len; uint64_t x = 0; |
||||
|
if ( rwflag != 0 ) |
||||
|
x = *int32p; |
||||
|
len = iguana_rwvarint(rwflag,serialized,&x); |
||||
|
if ( rwflag == 0 ) |
||||
|
*int32p = (int32_t)x; |
||||
|
return(len); |
||||
|
} |
||||
|
|
||||
|
int32_t iguana_rwstr(int32_t rwflag,uint8_t *serialized,int32_t maxlen,char *endianedp) |
||||
|
{ |
||||
|
int32_t vlen; uint64_t n; |
||||
|
if ( rwflag == 0 ) |
||||
|
{ |
||||
|
vlen = iguana_rwvarint(rwflag,serialized,&n); |
||||
|
memcpy(endianedp,&serialized[vlen],n); |
||||
|
((uint8_t *)endianedp)[n] = 0; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
n = strlen(endianedp); |
||||
|
if ( n > maxlen ) |
||||
|
n = maxlen; |
||||
|
vlen = iguana_rwvarint(rwflag,serialized,&n); |
||||
|
memcpy(&serialized[vlen],endianedp,n); |
||||
|
} |
||||
|
return((int32_t)(n + vlen)); |
||||
|
} |
||||
|
|
||||
|
int32_t iguana_rwmem(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp) |
||||
|
{ |
||||
|
if ( rwflag == 0 ) |
||||
|
memcpy(endianedp,serialized,len); |
||||
|
else memcpy(serialized,endianedp,len); |
||||
|
return(len); |
||||
|
} |
@ -0,0 +1,547 @@ |
|||||
|
# Copyrigh t (c) 2012 The Chromium Authors. All rights reserved.
|
||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||
|
# found in the LICENSE file.
|
||||
|
|
||||
|
#
|
||||
|
# GNU Make based build file. For details on GNU Make see:
|
||||
|
# http://www.gnu.org/software/make/manual/make.html
|
||||
|
#
|
||||
|
|
||||
|
#
|
||||
|
# Toolchain
|
||||
|
#
|
||||
|
# By default the VALID_TOOLCHAINS list contains pnacl, newlib and glibc. If
|
||||
|
# your project only builds in one or the other then this should be overridden
|
||||
|
# accordingly.
|
||||
|
#
|
||||
|
ifneq ($(ENABLE_BIONIC),) |
||||
|
ALL_TOOLCHAINS ?= pnacl newlib glibc clang-newlib bionic |
||||
|
else |
||||
|
ALL_TOOLCHAINS ?= pnacl newlib glibc clang-newlib |
||||
|
endif |
||||
|
|
||||
|
VALID_TOOLCHAINS ?= $(ALL_TOOLCHAINS) |
||||
|
TOOLCHAIN ?= $(word 1,$(VALID_TOOLCHAINS)) |
||||
|
|
||||
|
#
|
||||
|
# Top Make file, which we want to trigger a rebuild on if it changes
|
||||
|
#
|
||||
|
TOP_MAKE := $(word 1,$(MAKEFILE_LIST)) |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Figure out which OS we are running on.
|
||||
|
#
|
||||
|
GETOS := python $(NACL_SDK_ROOT)/tools/getos.py |
||||
|
NACL_CONFIG := python $(NACL_SDK_ROOT)/tools/nacl_config.py |
||||
|
FIXDEPS := python $(NACL_SDK_ROOT)/tools/fix_deps.py -c |
||||
|
OSNAME := $(shell $(GETOS)) |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# TOOLCHAIN=all recursively calls this Makefile for all VALID_TOOLCHAINS.
|
||||
|
#
|
||||
|
ifeq ($(TOOLCHAIN),all) |
||||
|
|
||||
|
# Define the default target
|
||||
|
all: |
||||
|
|
||||
|
#
|
||||
|
# Generate a new MAKE command for each TOOLCHAIN.
|
||||
|
#
|
||||
|
# Note: We use targets for each toolchain (instead of an explicit recipe) so
|
||||
|
# each toolchain can be built in parallel.
|
||||
|
#
|
||||
|
# $1 = Toolchain Name
|
||||
|
#
|
||||
|
define TOOLCHAIN_RULE |
||||
|
TOOLCHAIN_TARGETS += $(1)_TARGET |
||||
|
.PHONY: $(1)_TARGET |
||||
|
$(1)_TARGET: |
||||
|
+$(MAKE) TOOLCHAIN=$(1) $(MAKECMDGOALS) |
||||
|
endef |
||||
|
|
||||
|
#
|
||||
|
# The target for all versions
|
||||
|
#
|
||||
|
USABLE_TOOLCHAINS=$(filter $(OSNAME) $(ALL_TOOLCHAINS),$(VALID_TOOLCHAINS)) |
||||
|
|
||||
|
ifeq ($(NO_HOST_BUILDS),1) |
||||
|
USABLE_TOOLCHAINS:=$(filter-out $(OSNAME),$(USABLE_TOOLCHAINS)) |
||||
|
endif |
||||
|
|
||||
|
# Define the toolchain targets for all usable toolchains via the macro.
|
||||
|
$(foreach tool,$(USABLE_TOOLCHAINS),$(eval $(call TOOLCHAIN_RULE,$(tool)))) |
||||
|
|
||||
|
.PHONY: all clean install |
||||
|
all: $(TOOLCHAIN_TARGETS) |
||||
|
clean: $(TOOLCHAIN_TARGETS) |
||||
|
install: $(TOOLCHAIN_TARGETS) |
||||
|
|
||||
|
else # TOOLCHAIN=all
|
||||
|
|
||||
|
#
|
||||
|
# Verify we selected a valid toolchain for this example
|
||||
|
#
|
||||
|
ifeq (,$(findstring $(TOOLCHAIN),$(VALID_TOOLCHAINS))) |
||||
|
|
||||
|
# Only fail to build if this is a top-level make. When building recursively, we
|
||||
|
# don't care if an example can't build with this toolchain.
|
||||
|
ifeq ($(MAKELEVEL),0) |
||||
|
$(warning Availbile choices are: $(VALID_TOOLCHAINS)) |
||||
|
$(error Can not use TOOLCHAIN=$(TOOLCHAIN) on this example.) |
||||
|
else |
||||
|
|
||||
|
# Dummy targets for recursive make with unsupported toolchain...
|
||||
|
.PHONY: all clean install |
||||
|
all: |
||||
|
clean: |
||||
|
install: |
||||
|
|
||||
|
endif |
||||
|
|
||||
|
else # TOOLCHAIN is valid...
|
||||
|
|
||||
|
#
|
||||
|
# Build Configuration
|
||||
|
#
|
||||
|
# The SDK provides two sets of libraries, Debug and Release. Debug libraries
|
||||
|
# are compiled without optimizations to make debugging easier. By default
|
||||
|
# this will build a Release configuration. When debugging via "make debug",
|
||||
|
# build the debug configuration by default instead.
|
||||
|
#
|
||||
|
ifneq (,$(findstring debug,$(MAKECMDGOALS))) |
||||
|
CONFIG ?= Debug |
||||
|
else |
||||
|
CONFIG ?= Release |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Verify we selected a valid configuration for this example.
|
||||
|
#
|
||||
|
VALID_CONFIGS ?= Debug Release |
||||
|
ifeq (,$(findstring $(CONFIG),$(VALID_CONFIGS))) |
||||
|
$(warning Availbile choices are: $(VALID_CONFIGS)) |
||||
|
$(error Can not use CONFIG=$(CONFIG) on this example.) |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Note for Windows:
|
||||
|
# The GCC and LLVM toolchains (include the version of Make.exe that comes
|
||||
|
# with the SDK) expect and are capable of dealing with the '/' seperator.
|
||||
|
# For this reason, the tools in the SDK, including Makefiles and build scripts
|
||||
|
# have a preference for POSIX style command-line arguments.
|
||||
|
#
|
||||
|
# Keep in mind however that the shell is responsible for command-line escaping,
|
||||
|
# globbing, and variable expansion, so those may change based on which shell
|
||||
|
# is used. For Cygwin shells this can include automatic and incorrect expansion
|
||||
|
# of response files (files starting with '@').
|
||||
|
#
|
||||
|
# Disable DOS PATH warning when using Cygwin based NaCl tools on Windows.
|
||||
|
#
|
||||
|
ifeq ($(OSNAME),win) |
||||
|
# Always use cmd.exe as the shell on Windows. Otherwise Make may try to |
||||
|
# search the path for sh.exe. If it is found in a path with a space, the |
||||
|
# command will fail. |
||||
|
SHELL := cmd.exe |
||||
|
CYGWIN ?= nodosfilewarning |
||||
|
export CYGWIN |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# If NACL_SDK_ROOT is not already set, then set it relative to this makefile.
|
||||
|
#
|
||||
|
THIS_MAKEFILE := $(CURDIR)/$(lastword $(MAKEFILE_LIST)) |
||||
|
NACL_SDK_ROOT ?= $(realpath $(dir $(THIS_MAKEFILE))/..) |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Check that NACL_SDK_ROOT is set to a valid location.
|
||||
|
# We use the existence of tools/oshelpers.py to verify the validity of the SDK
|
||||
|
# root.
|
||||
|
#
|
||||
|
ifeq (,$(wildcard $(NACL_SDK_ROOT)/tools/oshelpers.py)) |
||||
|
$(error NACL_SDK_ROOT is set to an invalid location: $(NACL_SDK_ROOT)) |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# If this makefile is part of a valid nacl SDK, but NACL_SDK_ROOT is set
|
||||
|
# to a different location this is almost certainly a local configuration
|
||||
|
# error.
|
||||
|
#
|
||||
|
LOCAL_ROOT := $(realpath $(dir $(THIS_MAKEFILE))/..) |
||||
|
ifneq (,$(wildcard $(LOCAL_ROOT)/tools/oshelpers.py)) |
||||
|
ifneq ($(realpath $(NACL_SDK_ROOT)), $(realpath $(LOCAL_ROOT))) |
||||
|
$(error common.mk included from an SDK that does not match the current NACL_SDK_ROOT) |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Alias for standard POSIX file system commands
|
||||
|
#
|
||||
|
OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py |
||||
|
WHICH := $(OSHELPERS) which |
||||
|
ifdef V |
||||
|
RM := $(OSHELPERS) rm |
||||
|
CP := $(OSHELPERS) cp |
||||
|
MKDIR := $(OSHELPERS) mkdir |
||||
|
MV := $(OSHELPERS) mv |
||||
|
else |
||||
|
RM := @$(OSHELPERS) rm |
||||
|
CP := @$(OSHELPERS) cp |
||||
|
MKDIR := @$(OSHELPERS) mkdir |
||||
|
MV := @$(OSHELPERS) mv |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Compute path to requested NaCl Toolchain
|
||||
|
#
|
||||
|
TC_PATH := $(abspath $(NACL_SDK_ROOT)/../toolchain) |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Check for required minimum SDK version.
|
||||
|
# A makefile can declare NACL_SDK_VERSION_MIN of the form "<major>.<position>",
|
||||
|
# where <major> is the major Chromium version number, and <position> is the
|
||||
|
# Chromium Cr-Commit-Position number. eg. "39.295386".
|
||||
|
#
|
||||
|
ifdef NACL_SDK_VERSION_MIN |
||||
|
VERSION_CHECK:=$(shell $(GETOS) --check-version=$(NACL_SDK_VERSION_MIN) 2>&1) |
||||
|
ifneq ($(VERSION_CHECK),) |
||||
|
$(error $(VERSION_CHECK)) |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# The default target
|
||||
|
#
|
||||
|
# If no targets are specified on the command-line, the first target listed in
|
||||
|
# the makefile becomes the default target. By convention this is usually called
|
||||
|
# the 'all' target. Here we leave it blank to be first, but define it later
|
||||
|
#
|
||||
|
all: |
||||
|
.PHONY: all |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# The install target is used to install built libraries to thier final destination.
|
||||
|
# By default this is the NaCl SDK 'lib' folder.
|
||||
|
#
|
||||
|
install: |
||||
|
.PHONY: install |
||||
|
|
||||
|
ifdef SEL_LDR |
||||
|
STANDALONE = 1 |
||||
|
endif |
||||
|
|
||||
|
OUTBASE ?= . |
||||
|
ifdef STANDALONE |
||||
|
OUTDIR := $(OUTBASE)/$(TOOLCHAIN)/standalone_$(CONFIG) |
||||
|
else |
||||
|
OUTDIR := $(OUTBASE)/$(TOOLCHAIN)/$(CONFIG) |
||||
|
endif |
||||
|
STAMPDIR ?= $(OUTDIR) |
||||
|
LIBDIR ?= $(NACL_SDK_ROOT)/lib |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Target to remove temporary files
|
||||
|
#
|
||||
|
.PHONY: clean |
||||
|
clean: |
||||
|
$(RM) -f $(TARGET).nmf |
||||
|
$(RM) -rf $(OUTDIR) |
||||
|
$(RM) -rf user-data-dir |
||||
|
mkdir pnacl; mkdir pnacl/Release |
||||
|
cp Release/* nacl_io.stamp pnacl/Release; |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Rules for output directories.
|
||||
|
#
|
||||
|
# Output will be places in a directory name based on Toolchain and configuration
|
||||
|
# be default this will be "newlib/Debug". We use a python wrapped MKDIR to
|
||||
|
# proivde a cross platform solution. The use of '|' checks for existance instead
|
||||
|
# of timestamp, since the directory can update when files change.
|
||||
|
#
|
||||
|
%dir.stamp : |
||||
|
$(MKDIR) -p $(dir $@) |
||||
|
@echo Directory Stamp > $@ |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Dependency Macro
|
||||
|
#
|
||||
|
# $1 = Name of stamp
|
||||
|
# $2 = Directory for the sub-make
|
||||
|
# $3 = Extra Settings
|
||||
|
#
|
||||
|
define DEPEND_RULE |
||||
|
ifndef IGNORE_DEPS |
||||
|
.PHONY: rebuild_$(1) |
||||
|
|
||||
|
rebuild_$(1) :| $(STAMPDIR)/dir.stamp |
||||
|
ifeq (,$(2)) |
||||
|
+$(MAKE) -C $(NACL_SDK_ROOT)/src/$(1) STAMPDIR=$(abspath $(STAMPDIR)) $(abspath $(STAMPDIR)/$(1).stamp) $(3) |
||||
|
else |
||||
|
+$(MAKE) -C $(2) STAMPDIR=$(abspath $(STAMPDIR)) $(abspath $(STAMPDIR)/$(1).stamp) $(3) |
||||
|
endif |
||||
|
cp pnacl/Release/*.pexe pnacl/Release/*.bc pnacl/Release/SuperNET_API.nmf Release |
||||
|
|
||||
|
all: rebuild_$(1) |
||||
|
$(STAMPDIR)/$(1).stamp: rebuild_$(1) |
||||
|
|
||||
|
else |
||||
|
|
||||
|
.PHONY: $(STAMPDIR)/$(1).stamp |
||||
|
$(STAMPDIR)/$(1).stamp: |
||||
|
@echo Ignore $(1) |
||||
|
endif |
||||
|
endef |
||||
|
|
||||
|
ifeq ($(TOOLCHAIN),win) |
||||
|
ifdef STANDALONE |
||||
|
HOST_EXT = .exe |
||||
|
else |
||||
|
HOST_EXT = .dll |
||||
|
endif |
||||
|
else |
||||
|
ifdef STANDALONE |
||||
|
HOST_EXT = |
||||
|
else |
||||
|
HOST_EXT = .so |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Common Compile Options
|
||||
|
#
|
||||
|
# For example, -DNDEBUG is added to release builds by default
|
||||
|
# so that calls to assert(3) are not included in the build.
|
||||
|
#
|
||||
|
ifeq ($(CONFIG),Release) |
||||
|
POSIX_CFLAGS ?= -g -O2 -pthread -MMD -DNDEBUG |
||||
|
NACL_LDFLAGS ?= -O2 |
||||
|
PNACL_LDFLAGS ?= -O2 |
||||
|
else |
||||
|
POSIX_CFLAGS ?= -g -O0 -pthread -MMD -DNACL_SDK_DEBUG |
||||
|
endif |
||||
|
|
||||
|
NACL_CFLAGS ?= -Wno-long-long -Werror |
||||
|
NACL_CXXFLAGS ?= -Wno-long-long -Werror |
||||
|
NACL_LDFLAGS += -Wl,-as-needed -pthread |
||||
|
|
||||
|
#
|
||||
|
# Default Paths
|
||||
|
#
|
||||
|
INC_PATHS := $(shell $(NACL_CONFIG) -t $(TOOLCHAIN) --include-dirs) $(EXTRA_INC_PATHS) |
||||
|
LIB_PATHS := $(NACL_SDK_ROOT)/lib $(EXTRA_LIB_PATHS) |
||||
|
|
||||
|
#
|
||||
|
# Define a LOG macro that allow a command to be run in quiet mode where
|
||||
|
# the command echoed is not the same as the actual command executed.
|
||||
|
# The primary use case for this is to avoid echoing the full compiler
|
||||
|
# and linker command in the default case. Defining V=1 will restore
|
||||
|
# the verbose behavior
|
||||
|
#
|
||||
|
# $1 = The name of the tool being run
|
||||
|
# $2 = The target file being built
|
||||
|
# $3 = The full command to run
|
||||
|
#
|
||||
|
ifdef V |
||||
|
define LOG |
||||
|
$(3) |
||||
|
endef |
||||
|
else |
||||
|
ifeq ($(OSNAME),win) |
||||
|
define LOG |
||||
|
@echo $(1) $(2) && $(3) |
||||
|
endef |
||||
|
else |
||||
|
define LOG |
||||
|
@echo " $(1) $(2)" && $(3) |
||||
|
endef |
||||
|
endif |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Convert a source path to a object file path.
|
||||
|
#
|
||||
|
# $1 = Source Name
|
||||
|
# $2 = Arch suffix
|
||||
|
#
|
||||
|
define SRC_TO_OBJ |
||||
|
$(OUTDIR)/$(basename $(subst ..,__,$(1)))$(2).o |
||||
|
endef |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Convert a source path to a dependency file path.
|
||||
|
# We use the .deps extension for dependencies. These files are generated by
|
||||
|
# fix_deps.py based on the .d files which gcc generates. We don't reference
|
||||
|
# the .d files directly so that we can avoid the the case where the compile
|
||||
|
# failed but still generated a .d file (in that case the .d file would not
|
||||
|
# be processed by fix_deps.py)
|
||||
|
#
|
||||
|
# $1 = Source Name
|
||||
|
# $2 = Arch suffix
|
||||
|
#
|
||||
|
define SRC_TO_DEP |
||||
|
$(patsubst %.o,%.deps,$(call SRC_TO_OBJ,$(1),$(2))) |
||||
|
endef |
||||
|
|
||||
|
#
|
||||
|
# The gcc-generated deps files end in .d
|
||||
|
#
|
||||
|
define SRC_TO_DEP_PRE_FIXUP |
||||
|
$(patsubst %.o,%.d,$(call SRC_TO_OBJ,$(1),$(2))) |
||||
|
endef |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# If the requested toolchain is a NaCl or PNaCl toolchain, the use the
|
||||
|
# macros and targets defined in nacl.mk, otherwise use the host sepecific
|
||||
|
# macros and targets.
|
||||
|
#
|
||||
|
ifneq (,$(findstring $(TOOLCHAIN),linux mac)) |
||||
|
include $(NACL_SDK_ROOT)/tools/host_gcc.mk |
||||
|
endif |
||||
|
|
||||
|
ifneq (,$(findstring $(TOOLCHAIN),win)) |
||||
|
include $(NACL_SDK_ROOT)/tools/host_vc.mk |
||||
|
endif |
||||
|
|
||||
|
ifneq (,$(findstring $(TOOLCHAIN),glibc newlib bionic clang-newlib)) |
||||
|
include $(NACL_SDK_ROOT)/tools/nacl_gcc.mk |
||||
|
endif |
||||
|
|
||||
|
ifneq (,$(findstring $(TOOLCHAIN),pnacl)) |
||||
|
include $(NACL_SDK_ROOT)/tools/nacl_llvm.mk |
||||
|
endif |
||||
|
|
||||
|
#
|
||||
|
# File to redirect to to in order to hide output.
|
||||
|
#
|
||||
|
ifeq ($(OSNAME),win) |
||||
|
DEV_NULL = nul |
||||
|
else |
||||
|
DEV_NULL = /dev/null |
||||
|
endif |
||||
|
|
||||
|
|
||||
|
#
|
||||
|
# Variables for running examples with Chrome.
|
||||
|
#
|
||||
|
RUN_PY := python $(NACL_SDK_ROOT)/tools/run.py |
||||
|
#HTTPD_PY := python $(NACL_SDK_ROOT)/tools/httpd.py
|
||||
|
HTTPD_PY := python tools/httpd.py |
||||
|
|
||||
|
# Add this to launch Chrome with additional environment variables defined.
|
||||
|
# Each element should be specified as KEY=VALUE, with whitespace separating
|
||||
|
# key-value pairs. e.g.
|
||||
|
# CHROME_ENV=FOO=1 BAR=2 BAZ=3
|
||||
|
CHROME_ENV ?= |
||||
|
|
||||
|
# Additional arguments to pass to Chrome.
|
||||
|
CHROME_ARGS += --enable-nacl --enable-pnacl --no-first-run |
||||
|
CHROME_ARGS += --user-data-dir=$(CURDIR)/user-data-dir |
||||
|
|
||||
|
|
||||
|
# Paths to Debug and Release versions of the Host Pepper plugins
|
||||
|
PPAPI_DEBUG = $(abspath $(OSNAME)/Debug/$(TARGET)$(HOST_EXT));application/x-ppapi-debug |
||||
|
PPAPI_RELEASE = $(abspath $(OSNAME)/Release/$(TARGET)$(HOST_EXT));application/x-ppapi-release |
||||
|
|
||||
|
|
||||
|
SYSARCH := $(shell $(GETOS) --nacl-arch) |
||||
|
SEL_LDR_PATH := python $(NACL_SDK_ROOT)/tools/sel_ldr.py |
||||
|
|
||||
|
#
|
||||
|
# Common Compile Options
|
||||
|
#
|
||||
|
ifeq ($(CONFIG),Debug) |
||||
|
SEL_LDR_ARGS += --debug-libs |
||||
|
endif |
||||
|
|
||||
|
ifndef STANDALONE |
||||
|
#
|
||||
|
# Assign a sensible default to CHROME_PATH.
|
||||
|
#
|
||||
|
CHROME_PATH ?= $(shell $(GETOS) --chrome 2> $(DEV_NULL)) |
||||
|
|
||||
|
#
|
||||
|
# Verify we can find the Chrome executable if we need to launch it.
|
||||
|
#
|
||||
|
|
||||
|
NULL := |
||||
|
SPACE := $(NULL) # one space after NULL is required |
||||
|
CHROME_PATH_ESCAPE := $(subst $(SPACE),\ ,$(CHROME_PATH)) |
||||
|
|
||||
|
ifeq ($(OSNAME),win) |
||||
|
SANDBOX_ARGS := --no-sandbox |
||||
|
endif |
||||
|
|
||||
|
GDB_PATH := $(shell $(NACL_CONFIG) -t $(TOOLCHAIN) --tool=gdb) |
||||
|
|
||||
|
.PHONY: check_for_chrome |
||||
|
check_for_chrome: |
||||
|
ifeq (,$(wildcard $(CHROME_PATH_ESCAPE))) |
||||
|
$(warning No valid Chrome found at CHROME_PATH=$(CHROME_PATH)) |
||||
|
$(error Set CHROME_PATH via an environment variable, or command-line.) |
||||
|
else |
||||
|
$(warning Using chrome at: $(CHROME_PATH)) |
||||
|
endif |
||||
|
PAGE ?= index.html |
||||
|
PAGE_TC_CONFIG ?= "$(PAGE)?tc=$(TOOLCHAIN)&config=$(CONFIG)" |
||||
|
|
||||
|
.PHONY: run |
||||
|
run: check_for_chrome all $(PAGE) |
||||
|
$(RUN_PY) -C $(CURDIR) -P $(PAGE_TC_CONFIG) \
|
||||
|
$(addprefix -E ,$(CHROME_ENV)) -- "$(CHROME_PATH)" \
|
||||
|
$(CHROME_ARGS) \
|
||||
|
--register-pepper-plugins="$(PPAPI_DEBUG),$(PPAPI_RELEASE)" |
||||
|
|
||||
|
.PHONY: run_package |
||||
|
run_package: check_for_chrome all |
||||
|
@echo "$(TOOLCHAIN) $(CONFIG)" > $(CURDIR)/run_package_config |
||||
|
"$(CHROME_PATH)" --load-and-launch-app=$(CURDIR) $(CHROME_ARGS) |
||||
|
|
||||
|
GDB_ARGS += -D $(GDB_PATH) |
||||
|
# PNaCl's nexe is acquired with "remote get nexe <path>" instead of the NMF.
|
||||
|
ifeq (,$(findstring $(TOOLCHAIN),pnacl)) |
||||
|
GDB_ARGS += -D --eval-command="nacl-manifest $(abspath $(OUTDIR))/$(TARGET).nmf" |
||||
|
GDB_ARGS += -D $(GDB_DEBUG_TARGET) |
||||
|
endif |
||||
|
|
||||
|
.PHONY: debug |
||||
|
debug: check_for_chrome all $(PAGE) |
||||
|
$(RUN_PY) $(GDB_ARGS) \
|
||||
|
-C $(CURDIR) -P $(PAGE_TC_CONFIG) \
|
||||
|
$(addprefix -E ,$(CHROME_ENV)) -- "$(CHROME_PATH)" \
|
||||
|
$(CHROME_ARGS) $(SANDBOX_ARGS) --enable-nacl-debug \
|
||||
|
--register-pepper-plugins="$(PPAPI_DEBUG),$(PPAPI_RELEASE)" |
||||
|
|
||||
|
.PHONY: serve |
||||
|
serve: all |
||||
|
echo run tools/httpd.py |
||||
|
endif |
||||
|
|
||||
|
# uppercase aliases (for backward compatibility)
|
||||
|
.PHONY: CHECK_FOR_CHROME DEBUG LAUNCH RUN |
||||
|
CHECK_FOR_CHROME: check_for_chrome |
||||
|
DEBUG: debug |
||||
|
LAUNCH: run |
||||
|
RUN: run |
||||
|
|
||||
|
endif # TOOLCHAIN is valid...
|
||||
|
|
||||
|
endif # TOOLCHAIN=all
|
@ -0,0 +1,225 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
# Copyright (c) 2012 The Chromium Authors. All rights reserved. |
||||
|
# Use of this source code is governed by a BSD-style license that can be |
||||
|
# found in the LICENSE file. |
||||
|
|
||||
|
import argparse |
||||
|
import logging |
||||
|
import multiprocessing |
||||
|
import os |
||||
|
import socket |
||||
|
import sys |
||||
|
import time |
||||
|
|
||||
|
if sys.version_info < (2, 7, 0): |
||||
|
sys.stderr.write("python 2.7 or later is required run this script\n") |
||||
|
sys.exit(1) |
||||
|
|
||||
|
try: |
||||
|
# Python 3+ |
||||
|
from http.server import HTTPServer, SimpleHTTPRequestHandler |
||||
|
from urllib.parse import urlparse, parse_qs, urlsplit |
||||
|
except ImportError: |
||||
|
# Python 2.7 |
||||
|
from urlparse import urlparse, urlsplit, parse_qs |
||||
|
from BaseHTTPServer import HTTPServer |
||||
|
from SimpleHTTPServer import SimpleHTTPRequestHandler |
||||
|
|
||||
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
||||
|
NACL_SDK_ROOT = os.path.dirname(SCRIPT_DIR) |
||||
|
|
||||
|
# We only run from the examples directory so that not too much is exposed |
||||
|
# via this HTTP server. Everything in the directory is served, so there should |
||||
|
# never be anything potentially sensitive in the serving directory, especially |
||||
|
# if the machine might be a multi-user machine and not all users are trusted. |
||||
|
# We only serve via the loopback interface. |
||||
|
def SanityCheckDirectory(dirname): |
||||
|
abs_serve_dir = os.path.abspath(dirname) |
||||
|
|
||||
|
# Verify we don't serve anywhere above NACL_SDK_ROOT. |
||||
|
if abs_serve_dir[:len(NACL_SDK_ROOT)] == NACL_SDK_ROOT: |
||||
|
return |
||||
|
logging.error('For security, httpd.py should only be run from within the') |
||||
|
logging.error('example directory tree.') |
||||
|
logging.error('Attempting to serve from %s.' % abs_serve_dir) |
||||
|
logging.error('Run with --no-dir-check to bypass this check.') |
||||
|
sys.exit(1) |
||||
|
|
||||
|
|
||||
|
class SuperNetHTTPServer(HTTPServer): |
||||
|
def __init__(self, *args, **kwargs): |
||||
|
HTTPServer.__init__(self, *args) |
||||
|
self.running = True |
||||
|
self.result = 0 |
||||
|
|
||||
|
def Shutdown(self, result=0): |
||||
|
self.running = False |
||||
|
self.result = result |
||||
|
|
||||
|
|
||||
|
class SuperNetHTTPRequestHandler(SimpleHTTPRequestHandler): |
||||
|
def _SendNothingAndDie(self, result=0): |
||||
|
self.send_response(200, 'OK') |
||||
|
self.send_header('Content-type', 'text/html') |
||||
|
self.send_header('Content-length', '0') |
||||
|
self.end_headers() |
||||
|
self.server.Shutdown(result) |
||||
|
|
||||
|
def do_GET(self): |
||||
|
# Browsing to ?quit=1 will kill the server cleanly. |
||||
|
_, _, _, query, _ = urlsplit(self.path) |
||||
|
if query: |
||||
|
params = parse_qs(query) |
||||
|
if '1' in params.get('quit', []): |
||||
|
self._SendNothingAndDie() |
||||
|
return |
||||
|
|
||||
|
return SimpleHTTPRequestHandler.do_GET(self) |
||||
|
|
||||
|
|
||||
|
class LocalHTTPServer(object): |
||||
|
"""Class to start a local HTTP server as a child process.""" |
||||
|
|
||||
|
def __init__(self, dirname, port): |
||||
|
parent_conn, child_conn = multiprocessing.Pipe() |
||||
|
self.process = multiprocessing.Process( |
||||
|
target=_HTTPServerProcess, |
||||
|
args=(child_conn, dirname, port, {})) |
||||
|
self.process.start() |
||||
|
if parent_conn.poll(10): # wait 10 seconds |
||||
|
self.port = parent_conn.recv() |
||||
|
else: |
||||
|
raise Exception('Unable to launch HTTP server.') |
||||
|
|
||||
|
self.conn = parent_conn |
||||
|
|
||||
|
def ServeForever(self): |
||||
|
"""Serve until the child HTTP process tells us to stop. |
||||
|
|
||||
|
Returns: |
||||
|
The result from the child (as an errorcode), or 0 if the server was |
||||
|
killed not by the child (by KeyboardInterrupt for example). |
||||
|
""" |
||||
|
child_result = 0 |
||||
|
try: |
||||
|
# Block on this pipe, waiting for a response from the child process. |
||||
|
child_result = self.conn.recv() |
||||
|
except KeyboardInterrupt: |
||||
|
pass |
||||
|
finally: |
||||
|
self.Shutdown() |
||||
|
return child_result |
||||
|
|
||||
|
def ServeUntilSubprocessDies(self, process): |
||||
|
"""Serve until the child HTTP process tells us to stop or |subprocess| dies. |
||||
|
|
||||
|
Returns: |
||||
|
The result from the child (as an errorcode), or 0 if |subprocess| died, |
||||
|
or the server was killed some other way (by KeyboardInterrupt for |
||||
|
example). |
||||
|
""" |
||||
|
child_result = 0 |
||||
|
try: |
||||
|
while True: |
||||
|
if process.poll() is not None: |
||||
|
child_result = 0 |
||||
|
break |
||||
|
if self.conn.poll(): |
||||
|
child_result = self.conn.recv() |
||||
|
break |
||||
|
time.sleep(0) |
||||
|
except KeyboardInterrupt: |
||||
|
pass |
||||
|
finally: |
||||
|
self.Shutdown() |
||||
|
return child_result |
||||
|
|
||||
|
def Shutdown(self): |
||||
|
"""Send a message to the child HTTP server process and wait for it to |
||||
|
finish.""" |
||||
|
print("Shutting down server") |
||||
|
self.conn.send(False) |
||||
|
self.process.join() |
||||
|
|
||||
|
def GetURL(self, rel_url): |
||||
|
"""Get the full url for a file on the local HTTP server. |
||||
|
|
||||
|
Args: |
||||
|
rel_url: A URL fragment to convert to a full URL. For example, |
||||
|
GetURL('foobar.baz') -> 'http://127.0.0.1:1234/foobar.baz' |
||||
|
""" |
||||
|
return 'http://127.0.0.1:%d/%s' % (self.port, rel_url) |
||||
|
|
||||
|
|
||||
|
def _HTTPServerProcess(conn, dirname, port, server_kwargs): |
||||
|
"""Run a local httpserver with the given port or an ephemeral port. |
||||
|
|
||||
|
This function assumes it is run as a child process using multiprocessing. |
||||
|
|
||||
|
Args: |
||||
|
conn: A connection to the parent process. The child process sends |
||||
|
the local port, and waits for a message from the parent to |
||||
|
stop serving. It also sends a "result" back to the parent -- this can |
||||
|
be used to allow a client-side test to notify the server of results. |
||||
|
dirname: The directory to serve. All files are accessible through |
||||
|
http://127.0.0.1:<port>/path/to/filename. |
||||
|
port: The port to serve on. If 0, an ephemeral port will be chosen. |
||||
|
server_kwargs: A dict that will be passed as kwargs to the server. |
||||
|
""" |
||||
|
try: |
||||
|
os.chdir(dirname) |
||||
|
httpd = SuperNetHTTPServer(('', port), SuperNetHTTPRequestHandler, **server_kwargs) |
||||
|
except socket.error as e: |
||||
|
sys.stderr.write('Error creating SuperNetHTTPServer: %s\n' % e) |
||||
|
sys.exit(1) |
||||
|
|
||||
|
try: |
||||
|
conn.send(httpd.server_address[1]) # the chosen port number |
||||
|
httpd.timeout = 0.5 # seconds |
||||
|
while httpd.running: |
||||
|
# Flush output for MSVS Add-In. |
||||
|
sys.stdout.flush() |
||||
|
sys.stderr.flush() |
||||
|
httpd.handle_request() |
||||
|
if conn.poll(): |
||||
|
httpd.running = conn.recv() |
||||
|
except KeyboardInterrupt: |
||||
|
pass |
||||
|
finally: |
||||
|
conn.send(httpd.result) |
||||
|
conn.close() |
||||
|
|
||||
|
|
||||
|
def main(args): |
||||
|
parser = argparse.ArgumentParser() |
||||
|
parser.add_argument('-C', '--serve-dir', |
||||
|
help='Serve files out of this directory.', |
||||
|
default=os.path.abspath('.')) |
||||
|
parser.add_argument('-p', '--port', |
||||
|
help='Run server on this port.', default=7777) |
||||
|
parser.add_argument('--no-dir-check', '--no_dir_check', |
||||
|
help='No check to ensure serving from safe directory.', |
||||
|
dest='do_safe_check', action='store_false', default=True) |
||||
|
|
||||
|
# To enable bash completion for this command first install optcomplete |
||||
|
# and then add this line to your .bashrc: |
||||
|
# complete -F _optcomplete httpd.py |
||||
|
try: |
||||
|
import optcomplete |
||||
|
optcomplete.autocomplete(parser) |
||||
|
except ImportError: |
||||
|
pass |
||||
|
|
||||
|
options = parser.parse_args(args) |
||||
|
if options.do_safe_check: |
||||
|
SanityCheckDirectory(options.serve_dir) |
||||
|
|
||||
|
server = LocalHTTPServer(options.serve_dir, int(options.port)) |
||||
|
|
||||
|
# Serve until the client tells us to stop. When it does, it will give us an |
||||
|
# errorcode. |
||||
|
print(('Serving {0} on {1}...'.format(options.serve_dir, server.GetURL('')))) |
||||
|
return server.ServeForever() |
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
sys.exit(main(sys.argv[1:])) |
@ -0,0 +1,39 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef BUS_H_INCLUDED |
||||
|
#define BUS_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_PROTO_BUS 7 |
||||
|
|
||||
|
#define NN_BUS (NN_PROTO_BUS * 16 + 0) |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,37 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef INPROC_H_INCLUDED |
||||
|
#define INPROC_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_INPROC -1 |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,37 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef IPC_H_INCLUDED |
||||
|
#define IPC_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_IPC -2 |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,403 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2014 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_H_INCLUDED |
||||
|
#define NN_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#include <errno.h> |
||||
|
#include <stddef.h> |
||||
|
#include "nn_config.h" |
||||
|
|
||||
|
/* Handle DSO symbol visibility */ |
||||
|
#if defined NN_NO_EXPORTS |
||||
|
# define NN_EXPORT |
||||
|
#else |
||||
|
# if defined _WIN32 |
||||
|
# if defined NN_EXPORTS |
||||
|
# define NN_EXPORT __declspec(dllexport) |
||||
|
# else |
||||
|
# define NN_EXPORT __declspec(dllimport) |
||||
|
# endif |
||||
|
# else |
||||
|
# if defined __SUNPRO_C |
||||
|
# define NN_EXPORT __global |
||||
|
# elif (defined __GNUC__ && __GNUC__ >= 4) || \ |
||||
|
defined __INTEL_COMPILER || defined __clang__ |
||||
|
# define NN_EXPORT __attribute__ ((visibility("default"))) |
||||
|
# else |
||||
|
# define NN_EXPORT |
||||
|
# endif |
||||
|
# endif |
||||
|
#endif |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* ABI versioning support. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* Don't change this unless you know exactly what you're doing and have */ |
||||
|
/* read and understand the following documents: */ |
||||
|
/* www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html */ |
||||
|
/* www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html */ |
||||
|
|
||||
|
/* The current interface version. */ |
||||
|
#define NN_VERSION_CURRENT 2 |
||||
|
|
||||
|
/* The latest revision of the current interface. */ |
||||
|
#define NN_VERSION_REVISION 2 |
||||
|
|
||||
|
/* How many past interface versions are still supported. */ |
||||
|
#define NN_VERSION_AGE 2 |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Errors. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* A number random enough not to collide with different errno ranges on */ |
||||
|
/* different OSes. The assumption is that error_t is at least 32-bit type. */ |
||||
|
#define NN_HAUSNUMERO 156384712 |
||||
|
|
||||
|
/* On some platforms some standard POSIX errnos are not defined. */ |
||||
|
#ifndef ENOTSUP |
||||
|
#define ENOTSUP (NN_HAUSNUMERO + 1) |
||||
|
#endif |
||||
|
#ifndef EPROTONOSUPPORT |
||||
|
#define EPROTONOSUPPORT (NN_HAUSNUMERO + 2) |
||||
|
#endif |
||||
|
#ifndef ENOBUFS |
||||
|
#define ENOBUFS (NN_HAUSNUMERO + 3) |
||||
|
#endif |
||||
|
#ifndef ENETDOWN |
||||
|
#define ENETDOWN (NN_HAUSNUMERO + 4) |
||||
|
#endif |
||||
|
#ifndef EADDRINUSE |
||||
|
#define EADDRINUSE (NN_HAUSNUMERO + 5) |
||||
|
#endif |
||||
|
#ifndef EADDRNOTAVAIL |
||||
|
#define EADDRNOTAVAIL (NN_HAUSNUMERO + 6) |
||||
|
#endif |
||||
|
#ifndef ECONNREFUSED |
||||
|
#define ECONNREFUSED (NN_HAUSNUMERO + 7) |
||||
|
#endif |
||||
|
#ifndef EINPROGRESS |
||||
|
#define EINPROGRESS (NN_HAUSNUMERO + 8) |
||||
|
#endif |
||||
|
#ifndef ENOTSOCK |
||||
|
#define ENOTSOCK (NN_HAUSNUMERO + 9) |
||||
|
#endif |
||||
|
#ifndef EAFNOSUPPORT |
||||
|
#define EAFNOSUPPORT (NN_HAUSNUMERO + 10) |
||||
|
#endif |
||||
|
#ifndef EPROTO |
||||
|
#define EPROTO (NN_HAUSNUMERO + 11) |
||||
|
#endif |
||||
|
#ifndef EAGAIN |
||||
|
#define EAGAIN (NN_HAUSNUMERO + 12) |
||||
|
#endif |
||||
|
#ifndef EBADF |
||||
|
#define EBADF (NN_HAUSNUMERO + 13) |
||||
|
#endif |
||||
|
#ifndef EINVAL |
||||
|
#define EINVAL (NN_HAUSNUMERO + 14) |
||||
|
#endif |
||||
|
#ifndef EMFILE |
||||
|
#define EMFILE (NN_HAUSNUMERO + 15) |
||||
|
#endif |
||||
|
#ifndef EFAULT |
||||
|
#define EFAULT (NN_HAUSNUMERO + 16) |
||||
|
#endif |
||||
|
#ifndef EACCES |
||||
|
#define EACCES (NN_HAUSNUMERO + 17) |
||||
|
#endif |
||||
|
#ifndef EACCESS |
||||
|
#define EACCESS (EACCES) |
||||
|
#endif |
||||
|
#ifndef ENETRESET |
||||
|
#define ENETRESET (NN_HAUSNUMERO + 18) |
||||
|
#endif |
||||
|
#ifndef ENETUNREACH |
||||
|
#define ENETUNREACH (NN_HAUSNUMERO + 19) |
||||
|
#endif |
||||
|
#ifndef EHOSTUNREACH |
||||
|
#define EHOSTUNREACH (NN_HAUSNUMERO + 20) |
||||
|
#endif |
||||
|
#ifndef ENOTCONN |
||||
|
#define ENOTCONN (NN_HAUSNUMERO + 21) |
||||
|
#endif |
||||
|
#ifndef EMSGSIZE |
||||
|
#define EMSGSIZE (NN_HAUSNUMERO + 22) |
||||
|
#endif |
||||
|
#ifndef ETIMEDOUT |
||||
|
#define ETIMEDOUT (NN_HAUSNUMERO + 23) |
||||
|
#endif |
||||
|
#ifndef ECONNABORTED |
||||
|
#define ECONNABORTED (NN_HAUSNUMERO + 24) |
||||
|
#endif |
||||
|
#ifndef ECONNRESET |
||||
|
#define ECONNRESET (NN_HAUSNUMERO + 25) |
||||
|
#endif |
||||
|
#ifndef ENOPROTOOPT |
||||
|
#define ENOPROTOOPT (NN_HAUSNUMERO + 26) |
||||
|
#endif |
||||
|
#ifndef EISCONN |
||||
|
#define EISCONN (NN_HAUSNUMERO + 27) |
||||
|
#define NN_EISCONN_DEFINED |
||||
|
#endif |
||||
|
#ifndef ESOCKTNOSUPPORT |
||||
|
#define ESOCKTNOSUPPORT (NN_HAUSNUMERO + 28) |
||||
|
#endif |
||||
|
|
||||
|
/* Native nanomsg error codes. */ |
||||
|
#ifndef ETERM |
||||
|
#define ETERM (NN_HAUSNUMERO + 53) |
||||
|
#endif |
||||
|
#ifndef EFSM |
||||
|
#define EFSM (NN_HAUSNUMERO + 54) |
||||
|
#endif |
||||
|
|
||||
|
/* This function retrieves the errno as it is known to the library. */ |
||||
|
/* The goal of this function is to make the code 100% portable, including */ |
||||
|
/* where the library is compiled with certain CRT library (on Windows) and */ |
||||
|
/* linked to an application that uses different CRT library. */ |
||||
|
NN_EXPORT int nn_errno (void); |
||||
|
|
||||
|
/* Resolves system errors and native errors to human-readable string. */ |
||||
|
NN_EXPORT const char *nn_strerror (int errnum); |
||||
|
|
||||
|
|
||||
|
/* Returns the symbol name (e.g. "NN_REQ") and value at a specified index. */ |
||||
|
/* If the index is out-of-range, returns NULL and sets errno to EINVAL */ |
||||
|
/* General usage is to start at i=0 and iterate until NULL is returned. */ |
||||
|
NN_EXPORT const char *nn_symbol (int i, int *value); |
||||
|
|
||||
|
/* Constants that are returned in `ns` member of nn_symbol_properties */ |
||||
|
#define NN_NS_NAMESPACE 0 |
||||
|
#define NN_NS_VERSION 1 |
||||
|
#define NN_NS_DOMAIN 2 |
||||
|
#define NN_NS_TRANSPORT 3 |
||||
|
#define NN_NS_PROTOCOL 4 |
||||
|
#define NN_NS_OPTION_LEVEL 5 |
||||
|
#define NN_NS_SOCKET_OPTION 6 |
||||
|
#define NN_NS_TRANSPORT_OPTION 7 |
||||
|
#define NN_NS_OPTION_TYPE 8 |
||||
|
#define NN_NS_OPTION_UNIT 9 |
||||
|
#define NN_NS_FLAG 10 |
||||
|
#define NN_NS_ERROR 11 |
||||
|
#define NN_NS_LIMIT 12 |
||||
|
#define NN_NS_EVENT 13 |
||||
|
|
||||
|
/* Constants that are returned in `type` member of nn_symbol_properties */ |
||||
|
#define NN_TYPE_NONE 0 |
||||
|
#define NN_TYPE_INT 1 |
||||
|
#define NN_TYPE_STR 2 |
||||
|
|
||||
|
/* Constants that are returned in the `unit` member of nn_symbol_properties */ |
||||
|
#define NN_UNIT_NONE 0 |
||||
|
#define NN_UNIT_BYTES 1 |
||||
|
#define NN_UNIT_MILLISECONDS 2 |
||||
|
#define NN_UNIT_PRIORITY 3 |
||||
|
#define NN_UNIT_BOOLEAN 4 |
||||
|
|
||||
|
/* Structure that is returned from nn_symbol */ |
||||
|
struct nn_symbol_properties { |
||||
|
|
||||
|
/* The constant value */ |
||||
|
int value; |
||||
|
|
||||
|
/* The constant name */ |
||||
|
const char* name; |
||||
|
|
||||
|
/* The constant namespace, or zero for namespaces themselves */ |
||||
|
int ns; |
||||
|
|
||||
|
/* The option type for socket option constants */ |
||||
|
int type; |
||||
|
|
||||
|
/* The unit for the option value for socket option constants */ |
||||
|
int unit; |
||||
|
}; |
||||
|
|
||||
|
/* Fills in nn_symbol_properties structure and returns it's length */ |
||||
|
/* If the index is out-of-range, returns 0 */ |
||||
|
/* General usage is to start at i=0 and iterate until zero is returned. */ |
||||
|
NN_EXPORT int nn_symbol_info (int i, |
||||
|
struct nn_symbol_properties *buf, int buflen); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Helper function for shutting down multi-threaded applications. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
NN_EXPORT void nn_term (void); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Zero-copy support. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
#define NN_MSG ((size_t) -1) |
||||
|
|
||||
|
NN_EXPORT void *nn_allocmsg (size_t size, int type); |
||||
|
NN_EXPORT void *nn_reallocmsg (void *msg, size_t size); |
||||
|
NN_EXPORT int nn_freemsg (void *msg); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Socket definition. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
struct nn_iovec { |
||||
|
void *iov_base; |
||||
|
size_t iov_len; |
||||
|
}; |
||||
|
|
||||
|
struct nn_msghdr { |
||||
|
struct nn_iovec *msg_iov; |
||||
|
int msg_iovlen; |
||||
|
void *msg_control; |
||||
|
size_t msg_controllen; |
||||
|
}; |
||||
|
|
||||
|
struct nn_cmsghdr { |
||||
|
size_t cmsg_len; |
||||
|
int cmsg_level; |
||||
|
int cmsg_type; |
||||
|
}; |
||||
|
|
||||
|
/* Internal stuff. Not to be used directly. */ |
||||
|
NN_EXPORT struct nn_cmsghdr *nn_cmsg_nxthdr_ ( |
||||
|
const struct nn_msghdr *mhdr, |
||||
|
const struct nn_cmsghdr *cmsg); |
||||
|
#define NN_CMSG_ALIGN_(len) \ |
||||
|
(((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) |
||||
|
|
||||
|
/* POSIX-defined msghdr manipulation. */ |
||||
|
|
||||
|
#define NN_CMSG_FIRSTHDR(mhdr) \ |
||||
|
nn_cmsg_nxthdr_ ((struct nn_msghdr*) (mhdr), NULL) |
||||
|
|
||||
|
#define NN_CMSG_NXTHDR(mhdr, cmsg) \ |
||||
|
nn_cmsg_nxthdr_ ((struct nn_msghdr*) (mhdr), (struct nn_cmsghdr*) (cmsg)) |
||||
|
|
||||
|
#define NN_CMSG_DATA(cmsg) \ |
||||
|
((unsigned char*) (((struct nn_cmsghdr*) (cmsg)) + 1)) |
||||
|
|
||||
|
/* Extensions to POSIX defined by RFC 3542. */ |
||||
|
|
||||
|
#define NN_CMSG_SPACE(len) \ |
||||
|
(NN_CMSG_ALIGN_ (len) + NN_CMSG_ALIGN_ (sizeof (struct nn_cmsghdr))) |
||||
|
|
||||
|
#define NN_CMSG_LEN(len) \ |
||||
|
(NN_CMSG_ALIGN_ (sizeof (struct nn_cmsghdr)) + (len)) |
||||
|
|
||||
|
/* SP address families. */ |
||||
|
#define AF_SP 1 |
||||
|
#define AF_SP_RAW 2 |
||||
|
|
||||
|
/* Max size of an SP address. */ |
||||
|
#define NN_SOCKADDR_MAX 128 |
||||
|
|
||||
|
/* Socket option levels: Negative numbers are reserved for transports,
|
||||
|
positive for socket types. */ |
||||
|
#define NN_SOL_SOCKET 0 |
||||
|
|
||||
|
/* Generic socket options (NN_SOL_SOCKET level). */ |
||||
|
#define NN_LINGER 1 |
||||
|
#define NN_SNDBUF 2 |
||||
|
#define NN_RCVBUF 3 |
||||
|
#define NN_SNDTIMEO 4 |
||||
|
#define NN_RCVTIMEO 5 |
||||
|
#define NN_RECONNECT_IVL 6 |
||||
|
#define NN_RECONNECT_IVL_MAX 7 |
||||
|
#define NN_SNDPRIO 8 |
||||
|
#define NN_RCVPRIO 9 |
||||
|
#define NN_SNDFD 10 |
||||
|
#define NN_RCVFD 11 |
||||
|
#define NN_DOMAIN 12 |
||||
|
#define NN_PROTOCOL 13 |
||||
|
#define NN_IPV4ONLY 14 |
||||
|
#define NN_SOCKET_NAME 15 |
||||
|
#define NN_RCVMAXSIZE 16 |
||||
|
|
||||
|
/* Send/recv options. */ |
||||
|
#define NN_DONTWAIT 1 |
||||
|
|
||||
|
/* Ancillary data. */ |
||||
|
#define PROTO_SP 1 |
||||
|
#define SP_HDR 1 |
||||
|
|
||||
|
NN_EXPORT int nn_socket (int domain, int protocol); |
||||
|
NN_EXPORT int nn_close (int s); |
||||
|
NN_EXPORT int nn_setsockopt (int s, int level, int option, const void *optval, |
||||
|
size_t optvallen); |
||||
|
NN_EXPORT int nn_getsockopt (int s, int level, int option, void *optval, |
||||
|
size_t *optvallen); |
||||
|
NN_EXPORT int nn_bind (int s, const char *addr); |
||||
|
NN_EXPORT int nn_connect (int s, const char *addr); |
||||
|
NN_EXPORT int nn_shutdown (int s, int how); |
||||
|
NN_EXPORT int nn_send (int s, const void *buf, size_t len, int flags); |
||||
|
NN_EXPORT int nn_recv (int s, void *buf, size_t len, int flags); |
||||
|
NN_EXPORT int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags); |
||||
|
NN_EXPORT int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Socket mutliplexing support. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
#define NN_POLLIN 1 |
||||
|
#define NN_POLLOUT 2 |
||||
|
|
||||
|
struct nn_pollfd { |
||||
|
int fd; |
||||
|
short events; |
||||
|
short revents; |
||||
|
}; |
||||
|
|
||||
|
NN_EXPORT int nn_poll (struct nn_pollfd *fds, int nfds, int timeout); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Built-in support for devices. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
NN_EXPORT int nn_device (int s1, int s2); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Built-in support for multiplexers. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
NN_EXPORT int nn_tcpmuxd (int port); |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
#include "pair.h" |
||||
|
#include "bus.h" |
||||
|
#include "pubsub.h" |
||||
|
#include "reqrep.h" |
||||
|
#include "survey.h" |
||||
|
#include "pipeline.h" |
||||
|
|
@ -0,0 +1,75 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NNCONFIG_H_INCLUDED |
||||
|
#define NNCONFIG_H_INCLUDED |
||||
|
|
||||
|
#ifdef __APPLE__ |
||||
|
#define NN_HAVE_OSX 1 |
||||
|
#endif |
||||
|
|
||||
|
#define NN_HAVE_POLL 1 // must have
|
||||
|
#define NN_HAVE_SEMAPHORE 1 // must have
|
||||
|
|
||||
|
// need one of following 3, listed in order of precedence, used by efd*
|
||||
|
//#define NN_HAVE_EVENTFD 1
|
||||
|
//#define NN_HAVE_PIPE 1
|
||||
|
#define NN_HAVE_SOCKETPAIR 1 |
||||
|
|
||||
|
// need one of following 3, listed in order of precedence, used by poller*
|
||||
|
#define NN_USE_POLL 1 |
||||
|
//#define NN_USE_EPOLL 1
|
||||
|
//#define NN_USE_KQUEUE 1
|
||||
|
|
||||
|
#define NN_DISABLE_GETADDRINFO_A 1 |
||||
|
#define NN_USE_LITERAL_IFADDR 1 |
||||
|
#define NN_HAVE_STDINT 1 |
||||
|
|
||||
|
#define NN_HAVE_MSG_CONTROL 1 |
||||
|
//#define STANDALONE 1
|
||||
|
|
||||
|
#ifdef __PNACL |
||||
|
//#define FD_CLOEXEC 1
|
||||
|
|
||||
|
void PostMessage(const char* format, ...); |
||||
|
#include <glibc-compat/sys/uio.h> |
||||
|
#include <glibc-compat/sys/un.h> |
||||
|
#else |
||||
|
//#define NN_ENABLE_EXTRA 1
|
||||
|
#define PostMessage printf |
||||
|
#include <sys/uio.h> |
||||
|
#include <sys/un.h> |
||||
|
#endif |
||||
|
|
||||
|
/* Size of the buffer used for batch-reads of inbound data. To keep the
|
||||
|
performance optimal make sure that this value is larger than network MTU. */ |
||||
|
#define NN_USOCK_BATCH_SIZE (2048) |
||||
|
//#define NN_USOCK_BATCH_SIZE (_NN_USOCK_BATCH_SIZE - 5 - 256 - 16) // adjust for veclen/clen + sizeof(ctrl)
|
||||
|
|
||||
|
#if defined __PNACL || defined __APPLE__ |
||||
|
#define NN_USE_MYMSG 1 |
||||
|
#endif |
||||
|
|
||||
|
#define nn_errstr() nn_strerror(nn_errno()) |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,39 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef PAIR_H_INCLUDED |
||||
|
#define PAIR_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_PROTO_PAIR 1 |
||||
|
|
||||
|
#define NN_PAIR (NN_PROTO_PAIR * 16 + 0) |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,41 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef PIPELINE_H_INCLUDED |
||||
|
#define PIPELINE_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_PROTO_PIPELINE 5 |
||||
|
|
||||
|
#define NN_PUSH (NN_PROTO_PIPELINE * 16 + 0) |
||||
|
#define NN_PULL (NN_PROTO_PIPELINE * 16 + 1) |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,198 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_PROTOCOL_INCLUDED |
||||
|
#define NN_PROTOCOL_INCLUDED |
||||
|
|
||||
|
#include "utils/msg.h" |
||||
|
#include "utils/list.h" |
||||
|
#include "utils/int.h" |
||||
|
|
||||
|
#include <stddef.h> |
||||
|
|
||||
|
struct nn_ctx; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Pipe class. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* Any combination of following flags can be returned from successful call
|
||||
|
to nn_pipe_send or nn_pipe_recv. */ |
||||
|
|
||||
|
/* This flag means that the pipe can't be used for receiving (when returned
|
||||
|
from nn_pipe_recv()) or sending (when returned from nn_pipe_send()). |
||||
|
Protocol implementation should not send/recv messages from the pipe until |
||||
|
the pipe is revived by in()/out() function. */ |
||||
|
#define NN_PIPE_RELEASE 1 |
||||
|
|
||||
|
/* Specifies that received message is already split into header and body.
|
||||
|
This flag is used only by inproc transport to avoid merging and re-splitting |
||||
|
the messages passed with a single process. */ |
||||
|
#define NN_PIPE_PARSED 2 |
||||
|
|
||||
|
/* Events generated by the pipe. */ |
||||
|
#define NN_PIPE_IN 33987 |
||||
|
#define NN_PIPE_OUT 33988 |
||||
|
|
||||
|
struct nn_pipe; |
||||
|
|
||||
|
/* Associates opaque pointer to protocol-specific data with the pipe. */ |
||||
|
void nn_pipe_setdata (struct nn_pipe *self, void *data); |
||||
|
|
||||
|
/* Retrieves the opaque pointer associated with the pipe. */ |
||||
|
void *nn_pipe_getdata (struct nn_pipe *self); |
||||
|
|
||||
|
/* Send the message to the pipe. If successful, pipe takes ownership of the
|
||||
|
messages. */ |
||||
|
int nn_pipe_send (struct nn_pipe *self, struct nn_msg *msg); |
||||
|
|
||||
|
/* Receive a message from a pipe. 'msg' should not be initialised prior to
|
||||
|
the call. It will be initialised when the call succeeds. */ |
||||
|
int nn_pipe_recv (struct nn_pipe *self, struct nn_msg *msg); |
||||
|
|
||||
|
/* Get option for pipe. Mostly useful for endpoint-specific options */ |
||||
|
void nn_pipe_getopt (struct nn_pipe *self, int level, int option, |
||||
|
void *optval, size_t *optvallen); |
||||
|
|
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Base class for all socket types. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
struct nn_sockbase; |
||||
|
|
||||
|
/* Any combination of these events can be returned from 'events' virtual
|
||||
|
function. */ |
||||
|
#define NN_SOCKBASE_EVENT_IN 1 |
||||
|
#define NN_SOCKBASE_EVENT_OUT 2 |
||||
|
|
||||
|
/* To be implemented by individual socket types. */ |
||||
|
struct nn_sockbase_vfptr { |
||||
|
|
||||
|
/* Ask socket to stop. */ |
||||
|
void (*stop) (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Deallocate the socket. */ |
||||
|
void (*destroy) (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Management of pipes. 'add' registers a new pipe. The pipe cannot be used
|
||||
|
to send to or to be received from at the moment. 'rm' unregisters the |
||||
|
pipe. The pipe should not be used after this call as it may already be |
||||
|
deallocated. 'in' informs the socket that pipe is readable. 'out' |
||||
|
informs it that it is writable. */ |
||||
|
int (*add) (struct nn_sockbase *self, struct nn_pipe *pipe); |
||||
|
void (*rm) (struct nn_sockbase *self, struct nn_pipe *pipe); |
||||
|
void (*in) (struct nn_sockbase *self, struct nn_pipe *pipe); |
||||
|
void (*out) (struct nn_sockbase *self, struct nn_pipe *pipe); |
||||
|
|
||||
|
/* Return any combination of event flags defined above, thus specifying
|
||||
|
whether the socket should be readable, writable, both or none. */ |
||||
|
int (*events) (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Send a message to the socket. Returns -EAGAIN if it cannot be done at
|
||||
|
the moment or zero in case of success. */ |
||||
|
int (*send) (struct nn_sockbase *self, struct nn_msg *msg); |
||||
|
|
||||
|
/* Receive a message from the socket. Returns -EAGAIN if it cannot be done
|
||||
|
at the moment or zero in case of success. */ |
||||
|
int (*recv) (struct nn_sockbase *self, struct nn_msg *msg); |
||||
|
|
||||
|
/* Set a protocol specific option. */ |
||||
|
int (*setopt) (struct nn_sockbase *self, int level, int option, |
||||
|
const void *optval, size_t optvallen); |
||||
|
|
||||
|
/* Retrieve a protocol specific option. */ |
||||
|
int (*getopt) (struct nn_sockbase *self, int level, int option, |
||||
|
void *optval, size_t *optvallen); |
||||
|
}; |
||||
|
|
||||
|
struct nn_sockbase { |
||||
|
const struct nn_sockbase_vfptr *vfptr; |
||||
|
struct nn_sock *sock; |
||||
|
}; |
||||
|
|
||||
|
/* Initialise the socket base class. 'hint' is the opaque value passed to the
|
||||
|
nn_transport's 'create' function. */ |
||||
|
void nn_sockbase_init (struct nn_sockbase *self, |
||||
|
const struct nn_sockbase_vfptr *vfptr, void *hint); |
||||
|
|
||||
|
/* Terminate the socket base class. */ |
||||
|
void nn_sockbase_term (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Call this function when stopping is done. */ |
||||
|
void nn_sockbase_stopped (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Returns the AIO context associated with the socket. This function is
|
||||
|
useful when socket type implementation needs to create async objects, |
||||
|
such as timers. */ |
||||
|
struct nn_ctx *nn_sockbase_getctx (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Retrieve a NN_SOL_SOCKET-level option. */ |
||||
|
int nn_sockbase_getopt (struct nn_sockbase *self, int option, |
||||
|
void *optval, size_t *optvallen); |
||||
|
|
||||
|
/* Add some statistics for socket */ |
||||
|
void nn_sockbase_stat_increment (struct nn_sockbase *self, int name, |
||||
|
int increment); |
||||
|
|
||||
|
#define NN_STAT_CURRENT_SND_PRIORITY 401 |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* The socktype class. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* This structure defines a class factory for individual socket types. */ |
||||
|
|
||||
|
/* Specifies that the socket type can be never used to receive messages. */ |
||||
|
#define NN_SOCKTYPE_FLAG_NORECV 1 |
||||
|
|
||||
|
/* Specifies that the socket type can be never used to send messages. */ |
||||
|
#define NN_SOCKTYPE_FLAG_NOSEND 2 |
||||
|
|
||||
|
struct nn_socktype { |
||||
|
|
||||
|
/* Domain and protocol IDs as specified in nn_socket() function. */ |
||||
|
int domain; |
||||
|
int protocol; |
||||
|
|
||||
|
/* Any combination of the flags defined above. */ |
||||
|
int flags; |
||||
|
|
||||
|
/* Function to create specific socket type. 'sockbase' is the output
|
||||
|
parameter to return reference to newly created socket. This function |
||||
|
is called under global lock, so it is not possible that two sockets are |
||||
|
being created in parallel. */ |
||||
|
int (*create) (void *hint, struct nn_sockbase **sockbase); |
||||
|
|
||||
|
/* Returns 1 if the supplied socket type is a valid peer for this socket,
|
||||
|
0 otherwise. Note that the validation is done only within a single |
||||
|
SP protocol. Peers speaking other SP protocols are discarded by the |
||||
|
core and socket is not even asked to validate them. */ |
||||
|
int (*ispeer) (int socktype); |
||||
|
|
||||
|
/* This member is owned by the core. Never touch it directly from inside
|
||||
|
the protocol implementation. */ |
||||
|
struct nn_list_item item; |
||||
|
}; |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,43 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef PUBSUB_H_INCLUDED |
||||
|
#define PUBSUB_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_PROTO_PUBSUB 2 |
||||
|
|
||||
|
#define NN_PUB (NN_PROTO_PUBSUB * 16 + 0) |
||||
|
#define NN_SUB (NN_PROTO_PUBSUB * 16 + 1) |
||||
|
|
||||
|
#define NN_SUB_SUBSCRIBE 1 |
||||
|
#define NN_SUB_UNSUBSCRIBE 2 |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,52 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef REQREP_H_INCLUDED |
||||
|
#define REQREP_H_INCLUDED |
||||
|
|
||||
|
#include "nn.h" |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_PROTO_REQREP 3 |
||||
|
|
||||
|
#define NN_REQ (NN_PROTO_REQREP * 16 + 0) |
||||
|
#define NN_REP (NN_PROTO_REQREP * 16 + 1) |
||||
|
|
||||
|
#define NN_REQ_RESEND_IVL 1 |
||||
|
|
||||
|
typedef union nn_req_handle { |
||||
|
int i; |
||||
|
void *ptr; |
||||
|
} nn_req_handle; |
||||
|
|
||||
|
NN_EXPORT int nn_req_send (int s, nn_req_handle hndl, const void *buf, size_t len, int flags); |
||||
|
NN_EXPORT int nn_req_recv (int s, nn_req_handle *hndl, void *buf, size_t len, int flags); |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,46 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
Copyright 2015 Garrett D'Amore <garrett@damore.org> |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef SURVEY_H_INCLUDED |
||||
|
#define SURVEY_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_PROTO_SURVEY 6 |
||||
|
|
||||
|
/* NB: Version 0 used 16 + 0/1. That version lacked backtraces, and so
|
||||
|
is wire-incompatible with this version. */ |
||||
|
|
||||
|
#define NN_SURVEYOR (NN_PROTO_SURVEY * 16 + 2) |
||||
|
#define NN_RESPONDENT (NN_PROTO_SURVEY * 16 + 3) |
||||
|
|
||||
|
#define NN_SURVEYOR_DEADLINE 1 |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,39 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef TCP_H_INCLUDED |
||||
|
#define TCP_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_TCP -3 |
||||
|
|
||||
|
#define NN_TCP_NODELAY 1 |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,258 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2014 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_TRANSPORT_INCLUDED |
||||
|
#define NN_TRANSPORT_INCLUDED |
||||
|
|
||||
|
#include "nn.h" |
||||
|
|
||||
|
#include "aio/fsm.h" |
||||
|
|
||||
|
#include "utils/list.h" |
||||
|
#include "utils/msg.h" |
||||
|
#include "utils/int.h" |
||||
|
|
||||
|
#include <stddef.h> |
||||
|
|
||||
|
/* This is the API between the nanomsg core and individual transports. */ |
||||
|
|
||||
|
struct nn_sock; |
||||
|
struct nn_cp; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Container for transport-specific socket options. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
struct nn_optset; |
||||
|
|
||||
|
struct nn_optset_vfptr { |
||||
|
void (*destroy) (struct nn_optset *self); |
||||
|
int (*setopt) (struct nn_optset *self, int option, const void *optval, |
||||
|
size_t optvallen); |
||||
|
int (*getopt) (struct nn_optset *self, int option, void *optval, |
||||
|
size_t *optvallen); |
||||
|
}; |
||||
|
|
||||
|
struct nn_optset { |
||||
|
const struct nn_optset_vfptr *vfptr; |
||||
|
}; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* The base class for endpoints. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* The best way to think about endpoints is that endpoint is an object created
|
||||
|
by each nn_bind() or nn_connect() call. Each endpoint is associated with |
||||
|
exactly one address string (e.g. "tcp://127.0.0.1:5555"). */ |
||||
|
|
||||
|
struct nn_epbase; |
||||
|
|
||||
|
struct nn_epbase_vfptr { |
||||
|
|
||||
|
/* Ask the endpoint to stop itself. The endpoint is allowed to linger
|
||||
|
to send the pending outbound data. When done, it reports the fact by |
||||
|
invoking nn_epbase_stopped() function. */ |
||||
|
void (*stop) (struct nn_epbase *self); |
||||
|
|
||||
|
/* Deallocate the endpoint object. */ |
||||
|
void (*destroy) (struct nn_epbase *self); |
||||
|
}; |
||||
|
|
||||
|
struct nn_epbase { |
||||
|
const struct nn_epbase_vfptr *vfptr; |
||||
|
struct nn_ep *ep; |
||||
|
}; |
||||
|
|
||||
|
/* Creates a new endpoint. 'hint' parameter is an opaque value that
|
||||
|
was passed to transport's bind or connect function. */ |
||||
|
void nn_epbase_init (struct nn_epbase *self, |
||||
|
const struct nn_epbase_vfptr *vfptr, void *hint); |
||||
|
|
||||
|
/* Notify the user that stopping is done. */ |
||||
|
void nn_epbase_stopped (struct nn_epbase *self); |
||||
|
|
||||
|
/* Terminate the epbase object. */ |
||||
|
void nn_epbase_term (struct nn_epbase *self); |
||||
|
|
||||
|
/* Returns the AIO context associated with the endpoint. */ |
||||
|
struct nn_ctx *nn_epbase_getctx (struct nn_epbase *self); |
||||
|
|
||||
|
/* Returns the address string associated with this endpoint. */ |
||||
|
const char *nn_epbase_getaddr (struct nn_epbase *self); |
||||
|
|
||||
|
/* Retrieve value of a socket option. */ |
||||
|
void nn_epbase_getopt (struct nn_epbase *self, int level, int option, |
||||
|
void *optval, size_t *optvallen); |
||||
|
|
||||
|
/* Returns 1 is the specified socket type is a valid peer for this socket,
|
||||
|
or 0 otherwise. */ |
||||
|
int nn_epbase_ispeer (struct nn_epbase *self, int socktype); |
||||
|
|
||||
|
/* Notifies a monitoring system the error on this endpoint */ |
||||
|
//void nn_epbase_set_error(struct nn_epbase *self, int errnum);
|
||||
|
void nn_epbase_set_error(struct nn_epbase *self,int32_t errnum,char *fname,int32_t linenum); |
||||
|
|
||||
|
/* Notifies a monitoring system that error is gone */ |
||||
|
void nn_epbase_clear_error(struct nn_epbase *self); |
||||
|
|
||||
|
/* Increments statistics counters in the socket structure */ |
||||
|
void nn_epbase_stat_increment(struct nn_epbase *self, int name, int increment); |
||||
|
|
||||
|
|
||||
|
#define NN_STAT_ESTABLISHED_CONNECTIONS 101 |
||||
|
#define NN_STAT_ACCEPTED_CONNECTIONS 102 |
||||
|
#define NN_STAT_DROPPED_CONNECTIONS 103 |
||||
|
#define NN_STAT_BROKEN_CONNECTIONS 104 |
||||
|
#define NN_STAT_CONNECT_ERRORS 105 |
||||
|
#define NN_STAT_BIND_ERRORS 106 |
||||
|
#define NN_STAT_ACCEPT_ERRORS 107 |
||||
|
|
||||
|
#define NN_STAT_CURRENT_CONNECTIONS 201 |
||||
|
#define NN_STAT_INPROGRESS_CONNECTIONS 202 |
||||
|
#define NN_STAT_CURRENT_EP_ERRORS 203 |
||||
|
|
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* The base class for pipes. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* Pipe represents one "connection", i.e. perfectly ordered uni- or
|
||||
|
bi-directional stream of messages. One endpoint can create multiple pipes |
||||
|
(for example, bound TCP socket is an endpoint, individual accepted TCP |
||||
|
connections are represented by pipes. */ |
||||
|
|
||||
|
struct nn_pipebase; |
||||
|
|
||||
|
/* This value is returned by pipe's send and recv functions to signalise that
|
||||
|
more sends/recvs are not possible at the moment. From that moment on, |
||||
|
the core will stop invoking the function. To re-establish the message |
||||
|
flow nn_pipebase_received (respectively nn_pipebase_sent) should |
||||
|
be called. */ |
||||
|
#define NN_PIPEBASE_RELEASE 1 |
||||
|
|
||||
|
/* Specifies that received message is already split into header and body.
|
||||
|
This flag is used only by inproc transport to avoid merging and re-splitting |
||||
|
the messages passed with a single process. */ |
||||
|
#define NN_PIPEBASE_PARSED 2 |
||||
|
|
||||
|
struct nn_pipebase_vfptr { |
||||
|
|
||||
|
/* Send a message to the network. The function can return either error
|
||||
|
(negative number) or any combination of the flags defined above. */ |
||||
|
int (*send) (struct nn_pipebase *self, struct nn_msg *msg); |
||||
|
|
||||
|
/* Receive a message from the network. The function can return either error
|
||||
|
(negative number) or any combination of the flags defined above. */ |
||||
|
int (*recv) (struct nn_pipebase *self, struct nn_msg *msg); |
||||
|
}; |
||||
|
|
||||
|
/* Endpoint specific options. Same restrictions as for nn_pipebase apply */ |
||||
|
struct nn_ep_options |
||||
|
{ |
||||
|
int sndprio; |
||||
|
int rcvprio; |
||||
|
int ipv4only; |
||||
|
}; |
||||
|
|
||||
|
/* The member of this structure are used internally by the core. Never use
|
||||
|
or modify them directly from the transport. */ |
||||
|
struct nn_pipebase { |
||||
|
struct nn_fsm fsm; |
||||
|
const struct nn_pipebase_vfptr *vfptr; |
||||
|
uint8_t state; |
||||
|
uint8_t instate; |
||||
|
uint8_t outstate; |
||||
|
struct nn_sock *sock; |
||||
|
void *data; |
||||
|
struct nn_fsm_event in; |
||||
|
struct nn_fsm_event out; |
||||
|
struct nn_ep_options options; |
||||
|
}; |
||||
|
|
||||
|
/* Initialise the pipe. */ |
||||
|
void nn_pipebase_init (struct nn_pipebase *self,const struct nn_pipebase_vfptr *vfptr, struct nn_epbase *epbase); |
||||
|
|
||||
|
/* Terminate the pipe. */ |
||||
|
void nn_pipebase_term (struct nn_pipebase *self); |
||||
|
|
||||
|
/* Call this function once the connection is established. */ |
||||
|
int nn_pipebase_start (struct nn_pipebase *self); |
||||
|
|
||||
|
/* Call this function once the connection is broken. */ |
||||
|
void nn_pipebase_stop (struct nn_pipebase *self); |
||||
|
|
||||
|
/* Call this function when new message was fully received. */ |
||||
|
void nn_pipebase_received (struct nn_pipebase *self); |
||||
|
|
||||
|
/* Call this function when current outgoing message was fully sent. */ |
||||
|
void nn_pipebase_sent (struct nn_pipebase *self); |
||||
|
|
||||
|
/* Retrieve value of a socket option. */ |
||||
|
void nn_pipebase_getopt (struct nn_pipebase *self, int level, int option, |
||||
|
void *optval, size_t *optvallen); |
||||
|
|
||||
|
/* Returns 1 is the specified socket type is a valid peer for this socket,
|
||||
|
or 0 otherwise. */ |
||||
|
int nn_pipebase_ispeer (struct nn_pipebase *self, int socktype); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* The transport class. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
struct nn_transport { |
||||
|
|
||||
|
/* Name of the transport as it appears in the connection strings ("tcp",
|
||||
|
"ipc", "inproc" etc. */ |
||||
|
const char *name; |
||||
|
|
||||
|
/* ID of the transport. */ |
||||
|
int id; |
||||
|
|
||||
|
/* Following methods are guarded by a global critical section. Two of these
|
||||
|
function will never be invoked in parallel. The first is called when |
||||
|
the library is initialised, the second one when it is terminated, i.e. |
||||
|
when there are no more open sockets. Either of them can be set to NULL |
||||
|
if no specific initialisation/termination is needed. */ |
||||
|
void (*init) (void); |
||||
|
void (*term) (void); |
||||
|
|
||||
|
/* Each of these functions creates an endpoint and returns the newly
|
||||
|
created endpoint in 'epbase' parameter. 'hint' is in opaque pointer |
||||
|
to be passed to nn_epbase_init(). The epbase object can then be used |
||||
|
to retrieve the address to bind/connect to. These functions are guarded |
||||
|
by a socket-wide critical section. Two of these function will never be |
||||
|
invoked in parallel on the same socket. */ |
||||
|
int (*bind) (void *hint, struct nn_epbase **epbase); |
||||
|
int (*connect) (void *hint, struct nn_epbase **epbase); |
||||
|
|
||||
|
/* Create an object to hold transport-specific socket options.
|
||||
|
Set this member to NULL in case there are no transport-specific |
||||
|
socket options available. */ |
||||
|
struct nn_optset *(*optset) (void); |
||||
|
|
||||
|
/* This member is used exclusively by the core. Never touch it directly
|
||||
|
from the transport. */ |
||||
|
struct nn_list_item item; |
||||
|
}; |
||||
|
|
||||
|
#endif |
@ -0,0 +1,304 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
# Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
# of this software and associated documentation files (the "Software"), |
||||
|
# to deal in the Software without restriction, including without limitation |
||||
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
# and/or sell copies of the Software, and to permit persons to whom |
||||
|
# the Software is furnished to do so, subject to the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
# IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) |
||||
|
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) |
||||
|
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) |
||||
|
|
||||
|
set (NN_SOURCES |
||||
|
nn.h |
||||
|
inproc.h |
||||
|
ipc.h |
||||
|
tcp.h |
||||
|
ws.h |
||||
|
pair.h |
||||
|
pubsub.h |
||||
|
reqrep.h |
||||
|
pipeline.h |
||||
|
survey.h |
||||
|
bus.h |
||||
|
|
||||
|
core/ep.h |
||||
|
core/ep.c |
||||
|
core/epbase.c |
||||
|
core/global.h |
||||
|
core/global.c |
||||
|
core/pipe.c |
||||
|
core/poll.c |
||||
|
core/sock.h |
||||
|
core/sock.c |
||||
|
core/sockbase.c |
||||
|
core/symbol.c |
||||
|
|
||||
|
aio/ctx.h |
||||
|
aio/ctx.c |
||||
|
aio/fsm.h |
||||
|
aio/fsm.c |
||||
|
aio/poller.h |
||||
|
aio/poller.c |
||||
|
aio/poller_epoll.h |
||||
|
aio/poller_epoll.inc |
||||
|
aio/poller_kqueue.h |
||||
|
aio/poller_kqueue.inc |
||||
|
aio/poller_poll.h |
||||
|
aio/poller_poll.inc |
||||
|
aio/pool.h |
||||
|
aio/pool.c |
||||
|
aio/timer.h |
||||
|
aio/timer.c |
||||
|
aio/timerset.h |
||||
|
aio/timerset.c |
||||
|
aio/usock.h |
||||
|
aio/usock.c |
||||
|
aio/usock_posix.h |
||||
|
aio/usock_posix.inc |
||||
|
aio/usock_win.h |
||||
|
aio/usock_win.inc |
||||
|
aio/worker.h |
||||
|
aio/worker.c |
||||
|
aio/worker_posix.h |
||||
|
aio/worker_posix.inc |
||||
|
aio/worker_win.h |
||||
|
aio/worker_win.inc |
||||
|
|
||||
|
utils/alloc.h |
||||
|
utils/alloc.c |
||||
|
utils/atomic.h |
||||
|
utils/atomic.c |
||||
|
utils/attr.h |
||||
|
utils/chunk.h |
||||
|
utils/chunk.c |
||||
|
utils/chunkref.h |
||||
|
utils/chunkref.c |
||||
|
utils/clock.h |
||||
|
utils/clock.c |
||||
|
utils/closefd.h |
||||
|
utils/closefd.c |
||||
|
utils/cont.h |
||||
|
utils/efd.h |
||||
|
utils/efd.c |
||||
|
utils/efd_eventfd.h |
||||
|
utils/efd_eventfd.inc |
||||
|
utils/efd_pipe.h |
||||
|
utils/efd_pipe.inc |
||||
|
utils/efd_socketpair.h |
||||
|
utils/efd_socketpair.inc |
||||
|
utils/efd_win.h |
||||
|
utils/efd_win.inc |
||||
|
utils/err.h |
||||
|
utils/err.c |
||||
|
utils/fast.h |
||||
|
utils/fd.h |
||||
|
utils/glock.h |
||||
|
utils/glock.c |
||||
|
utils/hash.h |
||||
|
utils/hash.c |
||||
|
utils/int.h |
||||
|
utils/list.h |
||||
|
utils/list.c |
||||
|
utils/msg.h |
||||
|
utils/msg.c |
||||
|
utils/mutex.h |
||||
|
utils/mutex.c |
||||
|
utils/queue.h |
||||
|
utils/queue.c |
||||
|
utils/random.h |
||||
|
utils/random.c |
||||
|
utils/sem.h |
||||
|
utils/sem.c |
||||
|
utils/sleep.h |
||||
|
utils/sleep.c |
||||
|
utils/thread.h |
||||
|
utils/thread.c |
||||
|
utils/thread_posix.h |
||||
|
utils/thread_posix.inc |
||||
|
utils/thread_win.h |
||||
|
utils/thread_win.inc |
||||
|
utils/wire.h |
||||
|
utils/wire.c |
||||
|
|
||||
|
devices/device.h |
||||
|
devices/device.c |
||||
|
devices/tcpmuxd.c |
||||
|
|
||||
|
protocols/utils/dist.h |
||||
|
protocols/utils/dist.c |
||||
|
protocols/utils/excl.h |
||||
|
protocols/utils/excl.c |
||||
|
protocols/utils/fq.h |
||||
|
protocols/utils/fq.c |
||||
|
protocols/utils/lb.h |
||||
|
protocols/utils/lb.c |
||||
|
protocols/utils/priolist.h |
||||
|
protocols/utils/priolist.c |
||||
|
|
||||
|
protocols/bus/bus.h |
||||
|
protocols/bus/bus.c |
||||
|
protocols/bus/xbus.h |
||||
|
protocols/bus/xbus.c |
||||
|
|
||||
|
protocols/pipeline/push.h |
||||
|
protocols/pipeline/push.c |
||||
|
protocols/pipeline/pull.h |
||||
|
protocols/pipeline/pull.c |
||||
|
protocols/pipeline/xpull.h |
||||
|
protocols/pipeline/xpull.c |
||||
|
protocols/pipeline/xpush.h |
||||
|
protocols/pipeline/xpush.c |
||||
|
|
||||
|
protocols/pair/pair.h |
||||
|
protocols/pair/pair.c |
||||
|
protocols/pair/xpair.h |
||||
|
protocols/pair/xpair.c |
||||
|
|
||||
|
protocols/pubsub/pub.h |
||||
|
protocols/pubsub/pub.c |
||||
|
protocols/pubsub/sub.h |
||||
|
protocols/pubsub/sub.c |
||||
|
protocols/pubsub/trie.h |
||||
|
protocols/pubsub/trie.c |
||||
|
protocols/pubsub/xpub.h |
||||
|
protocols/pubsub/xpub.c |
||||
|
protocols/pubsub/xsub.h |
||||
|
protocols/pubsub/xsub.c |
||||
|
|
||||
|
protocols/reqrep/req.h |
||||
|
protocols/reqrep/req.c |
||||
|
protocols/reqrep/rep.h |
||||
|
protocols/reqrep/rep.c |
||||
|
protocols/reqrep/task.h |
||||
|
protocols/reqrep/task.c |
||||
|
protocols/reqrep/xrep.h |
||||
|
protocols/reqrep/xrep.c |
||||
|
protocols/reqrep/xreq.h |
||||
|
protocols/reqrep/xreq.c |
||||
|
|
||||
|
protocols/survey/respondent.h |
||||
|
protocols/survey/respondent.c |
||||
|
protocols/survey/surveyor.h |
||||
|
protocols/survey/surveyor.c |
||||
|
protocols/survey/xrespondent.h |
||||
|
protocols/survey/xrespondent.c |
||||
|
protocols/survey/xsurveyor.h |
||||
|
protocols/survey/xsurveyor.c |
||||
|
|
||||
|
transports/utils/backoff.h |
||||
|
transports/utils/backoff.c |
||||
|
transports/utils/dns.h |
||||
|
transports/utils/dns.c |
||||
|
transports/utils/dns_getaddrinfo.h |
||||
|
transports/utils/dns_getaddrinfo.inc |
||||
|
transports/utils/dns_getaddrinfo_a.h |
||||
|
transports/utils/dns_getaddrinfo_a.inc |
||||
|
transports/utils/iface.h |
||||
|
transports/utils/iface.c |
||||
|
transports/utils/literal.h |
||||
|
transports/utils/literal.c |
||||
|
transports/utils/port.h |
||||
|
transports/utils/port.c |
||||
|
transports/utils/streamhdr.h |
||||
|
transports/utils/streamhdr.c |
||||
|
transports/utils/base64.h |
||||
|
transports/utils/base64.c |
||||
|
|
||||
|
transports/inproc/binproc.h |
||||
|
transports/inproc/binproc.c |
||||
|
transports/inproc/cinproc.h |
||||
|
transports/inproc/cinproc.c |
||||
|
transports/inproc/inproc.h |
||||
|
transports/inproc/inproc.c |
||||
|
transports/inproc/ins.h |
||||
|
transports/inproc/ins.c |
||||
|
transports/inproc/msgqueue.h |
||||
|
transports/inproc/msgqueue.c |
||||
|
transports/inproc/sinproc.h |
||||
|
transports/inproc/sinproc.c |
||||
|
|
||||
|
transports/ipc/aipc.h |
||||
|
transports/ipc/aipc.c |
||||
|
transports/ipc/bipc.h |
||||
|
transports/ipc/bipc.c |
||||
|
transports/ipc/cipc.h |
||||
|
transports/ipc/cipc.c |
||||
|
transports/ipc/ipc.h |
||||
|
transports/ipc/ipc.c |
||||
|
transports/ipc/sipc.h |
||||
|
transports/ipc/sipc.c |
||||
|
|
||||
|
transports/tcp/atcp.h |
||||
|
transports/tcp/atcp.c |
||||
|
transports/tcp/btcp.h |
||||
|
transports/tcp/btcp.c |
||||
|
transports/tcp/ctcp.h |
||||
|
transports/tcp/ctcp.c |
||||
|
transports/tcp/stcp.h |
||||
|
transports/tcp/stcp.c |
||||
|
transports/tcp/tcp.h |
||||
|
transports/tcp/tcp.c |
||||
|
|
||||
|
transports/tcpmux/atcpmux.h |
||||
|
transports/tcpmux/atcpmux.c |
||||
|
transports/tcpmux/btcpmux.h |
||||
|
transports/tcpmux/btcpmux.c |
||||
|
transports/tcpmux/ctcpmux.h |
||||
|
transports/tcpmux/ctcpmux.c |
||||
|
transports/tcpmux/stcpmux.h |
||||
|
transports/tcpmux/stcpmux.c |
||||
|
transports/tcpmux/tcpmux.h |
||||
|
transports/tcpmux/tcpmux.c |
||||
|
|
||||
|
transports/ws/aws.h |
||||
|
transports/ws/aws.c |
||||
|
transports/ws/bws.h |
||||
|
transports/ws/bws.c |
||||
|
transports/ws/cws.h |
||||
|
transports/ws/cws.c |
||||
|
transports/ws/sws.h |
||||
|
transports/ws/sws.c |
||||
|
transports/ws/ws.h |
||||
|
transports/ws/ws.c |
||||
|
transports/ws/ws_handshake.h |
||||
|
transports/ws/ws_handshake.c |
||||
|
transports/ws/sha1.h |
||||
|
transports/ws/sha1.c |
||||
|
) |
||||
|
|
||||
|
if (WIN32) |
||||
|
LIST (APPEND NN_SOURCES |
||||
|
utils/win.h |
||||
|
) |
||||
|
endif () |
||||
|
|
||||
|
add_library (nanomsg SHARED ${NN_SOURCES}) |
||||
|
|
||||
|
add_definitions (-DNN_EXPORTS) |
||||
|
add_definitions (-DNN_USE_LITERAL_IFADDR) |
||||
|
|
||||
|
target_link_libraries (nanomsg ws2_32) |
||||
|
target_link_libraries (nanomsg Mswsock.lib) |
||||
|
target_link_libraries (nanomsg Advapi32.lib) |
||||
|
|
||||
|
install(TARGETS nanomsg |
||||
|
ARCHIVE DESTINATION lib |
||||
|
LIBRARY DESTINATION lib |
||||
|
RUNTIME DESTINATION bin) |
@ -0,0 +1,2 @@ |
|||||
|
This directory contains all headers that interconnect various parts of |
||||
|
the system. The public API, the interface for protocols and transports etc. |
@ -0,0 +1,119 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "ctx.h" |
||||
|
|
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/cont.h" |
||||
|
#include "../utils/fast.h" |
||||
|
|
||||
|
void nn_ctx_init (struct nn_ctx *self, struct nn_pool *pool, |
||||
|
nn_ctx_onleave onleave) |
||||
|
{ |
||||
|
nn_mutex_init (&self->sync); |
||||
|
self->pool = pool; |
||||
|
nn_queue_init (&self->events); |
||||
|
nn_queue_init (&self->eventsto); |
||||
|
self->onleave = onleave; |
||||
|
} |
||||
|
|
||||
|
void nn_ctx_term (struct nn_ctx *self) |
||||
|
{ |
||||
|
nn_queue_term (&self->eventsto); |
||||
|
nn_queue_term (&self->events); |
||||
|
nn_mutex_term (&self->sync); |
||||
|
} |
||||
|
|
||||
|
void nn_ctx_enter (struct nn_ctx *self) |
||||
|
{ |
||||
|
nn_mutex_lock (&self->sync); |
||||
|
} |
||||
|
|
||||
|
void nn_ctx_leave(struct nn_ctx *self) |
||||
|
{ |
||||
|
struct nn_queue_item *item; |
||||
|
struct nn_fsm_event *event; |
||||
|
struct nn_queue eventsto; |
||||
|
//PostMessage("nn_ctx_leave\n");
|
||||
|
while ( 1 ) // Process any queued events before leaving the context
|
||||
|
{ |
||||
|
item = nn_queue_pop(&self->events); |
||||
|
//PostMessage("nn_ctx_leave nn_queue_pop: %p\n",item);
|
||||
|
event = nn_cont(item,struct nn_fsm_event,item); |
||||
|
//PostMessage("nn_ctx_leave event: %p\n",event);
|
||||
|
if ( !event ) |
||||
|
break; |
||||
|
//PostMessage("nn_ctx_leave nn_fsm_event_process event.%p\n",event);
|
||||
|
nn_fsm_event_process(event); |
||||
|
//PostMessage("nn_ctx_leave nn_fsm_event_process done.%p\n",event);
|
||||
|
} |
||||
|
//PostMessage("nn_ctx_leave: notify owner\n");
|
||||
|
if ( nn_fast(self->onleave != NULL) ) // Notify the owner that we are leaving the context
|
||||
|
{ |
||||
|
//PostMessage("nn_ctx_leave notify owner.%p\n",self);
|
||||
|
self->onleave (self); |
||||
|
} |
||||
|
if ( nn_queue_empty(&self->eventsto) ) // Shortcut in the case there are no external events
|
||||
|
{ |
||||
|
//PostMessage("nn_ctx_leave: shortcut\n");
|
||||
|
nn_mutex_unlock(&self->sync); |
||||
|
//PostMessage("nn_ctx_leave: no external evels\n");
|
||||
|
return; |
||||
|
} |
||||
|
// Make a copy of the queue of the external events so that it does not get corrupted once we unlock the context
|
||||
|
eventsto = self->eventsto; |
||||
|
//PostMessage("nn_ctx_leave copy queue.%p\n",eventsto);
|
||||
|
nn_queue_init (&self->eventsto); |
||||
|
nn_mutex_unlock (&self->sync); |
||||
|
//PostMessage("nn_ctx_leave copied queue.%p\n",eventsto);
|
||||
|
while ( 1 ) // Process any queued external events. Before processing each event lock the context it belongs to
|
||||
|
{ |
||||
|
item = nn_queue_pop(&eventsto); |
||||
|
event = nn_cont(item,struct nn_fsm_event,item); |
||||
|
if ( !event ) |
||||
|
break; |
||||
|
//PostMessage("process event lock: enter\n");
|
||||
|
nn_ctx_enter (event->fsm->ctx); |
||||
|
//PostMessage("process event lock\n");
|
||||
|
nn_fsm_event_process (event); |
||||
|
//PostMessage("process event lock: leave\n");
|
||||
|
nn_ctx_leave (event->fsm->ctx); |
||||
|
//PostMessage("nn_ctx_leave even lock\n");
|
||||
|
} |
||||
|
nn_queue_term(&eventsto); |
||||
|
} |
||||
|
|
||||
|
struct nn_worker *nn_ctx_choose_worker (struct nn_ctx *self) |
||||
|
{ |
||||
|
return nn_pool_choose_worker (self->pool); |
||||
|
} |
||||
|
|
||||
|
void nn_ctx_raise (struct nn_ctx *self, struct nn_fsm_event *event) |
||||
|
{ |
||||
|
nn_queue_push (&self->events, &event->item); |
||||
|
} |
||||
|
|
||||
|
void nn_ctx_raiseto (struct nn_ctx *self, struct nn_fsm_event *event) |
||||
|
{ |
||||
|
nn_queue_push (&self->eventsto, &event->item); |
||||
|
} |
||||
|
|
@ -0,0 +1,58 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_CTX_INCLUDED |
||||
|
#define NN_CTX_INCLUDED |
||||
|
|
||||
|
#include "../utils/mutex.h" |
||||
|
#include "../utils/queue.h" |
||||
|
|
||||
|
#include "worker.h" |
||||
|
#include "pool.h" |
||||
|
#include "fsm.h" |
||||
|
|
||||
|
/* AIO context for objects using AIO subsystem. */ |
||||
|
|
||||
|
typedef void (*nn_ctx_onleave) (struct nn_ctx *self); |
||||
|
|
||||
|
struct nn_ctx { |
||||
|
struct nn_mutex sync; |
||||
|
struct nn_pool *pool; |
||||
|
struct nn_queue events; |
||||
|
struct nn_queue eventsto; |
||||
|
nn_ctx_onleave onleave; |
||||
|
}; |
||||
|
|
||||
|
void nn_ctx_init (struct nn_ctx *self, struct nn_pool *pool, |
||||
|
nn_ctx_onleave onleave); |
||||
|
void nn_ctx_term (struct nn_ctx *self); |
||||
|
|
||||
|
void nn_ctx_enter (struct nn_ctx *self); |
||||
|
void nn_ctx_leave (struct nn_ctx *self); |
||||
|
|
||||
|
struct nn_worker *nn_ctx_choose_worker (struct nn_ctx *self); |
||||
|
|
||||
|
void nn_ctx_raise (struct nn_ctx *self, struct nn_fsm_event *event); |
||||
|
void nn_ctx_raiseto (struct nn_ctx *self, struct nn_fsm_event *event); |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,178 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "fsm.h" |
||||
|
#include "ctx.h" |
||||
|
|
||||
|
#include "../utils/err.h" |
||||
|
|
||||
|
#include <stddef.h> |
||||
|
|
||||
|
#define NN_FSM_STATE_IDLE 1 |
||||
|
#define NN_FSM_STATE_ACTIVE 2 |
||||
|
#define NN_FSM_STATE_STOPPING 3 |
||||
|
|
||||
|
void nn_fsm_event_init(struct nn_fsm_event *self) |
||||
|
{ |
||||
|
self->fsm = NULL; |
||||
|
self->src = -1; |
||||
|
self->srcptr = NULL; |
||||
|
self->type = -1; |
||||
|
nn_queue_item_init(&self->item); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_event_term(struct nn_fsm_event *self) { nn_queue_item_term(&self->item); } |
||||
|
|
||||
|
int nn_fsm_event_active(struct nn_fsm_event *self) { return nn_queue_item_isinqueue (&self->item); } |
||||
|
|
||||
|
void nn_fsm_event_process(struct nn_fsm_event *self) |
||||
|
{ |
||||
|
int32_t src,type; void *srcptr; |
||||
|
//PostMessage("fsm_event_process.%p\n",self);
|
||||
|
src = self->src; |
||||
|
type = self->type; |
||||
|
srcptr = self->srcptr; |
||||
|
self->src = -1; |
||||
|
self->type = -1; |
||||
|
self->srcptr = NULL; |
||||
|
//PostMessage("fsm_event_process call nn_fsm_feed.(%p %d).%p\n",src,type,srcptr);
|
||||
|
nn_fsm_feed(self->fsm,src,type,srcptr); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_feed(struct nn_fsm *self,int32_t src,int32_t type,void *srcptr) |
||||
|
{ |
||||
|
//PostMessage("nn_fsm_feed.(%d %d) state.%d vs %d, fn.%p shutdown.%p\n",src,type,self->state,NN_FSM_STATE_STOPPING,self->fn,self->shutdown_fn);
|
||||
|
if ( nn_slow(self->state != NN_FSM_STATE_STOPPING) ) |
||||
|
self->fn(self,src,type,srcptr); |
||||
|
else self->shutdown_fn(self,src,type,srcptr); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_init_root(struct nn_fsm *self, nn_fsm_fn fn,nn_fsm_fn shutdown_fn, struct nn_ctx *ctx) |
||||
|
{ |
||||
|
self->fn = fn; |
||||
|
self->shutdown_fn = shutdown_fn; |
||||
|
self->state = NN_FSM_STATE_IDLE; |
||||
|
self->src = -1; |
||||
|
self->srcptr = NULL; |
||||
|
self->owner = NULL; |
||||
|
self->ctx = ctx; |
||||
|
nn_fsm_event_init (&self->stopped); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_init (struct nn_fsm *self, nn_fsm_fn fn, |
||||
|
nn_fsm_fn shutdown_fn, int src, void *srcptr, struct nn_fsm *owner) |
||||
|
{ |
||||
|
self->fn = fn; |
||||
|
self->shutdown_fn = shutdown_fn; |
||||
|
self->state = NN_FSM_STATE_IDLE; |
||||
|
self->src = src; |
||||
|
self->srcptr = srcptr; |
||||
|
self->owner = owner; |
||||
|
self->ctx = owner->ctx; |
||||
|
nn_fsm_event_init (&self->stopped); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_term (struct nn_fsm *self) |
||||
|
{ |
||||
|
nn_assert (nn_fsm_isidle (self)); |
||||
|
nn_fsm_event_term (&self->stopped); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_start (struct nn_fsm *self) |
||||
|
{ |
||||
|
nn_assert (nn_fsm_isidle (self)); |
||||
|
self->fn (self, NN_FSM_ACTION, NN_FSM_START, NULL); |
||||
|
self->state = NN_FSM_STATE_ACTIVE; |
||||
|
} |
||||
|
|
||||
|
int nn_fsm_isidle (struct nn_fsm *self) |
||||
|
{ |
||||
|
return self->state == NN_FSM_STATE_IDLE && |
||||
|
!nn_fsm_event_active (&self->stopped) ? 1 : 0; |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_stop (struct nn_fsm *self) |
||||
|
{ |
||||
|
/* If stopping of the state machine was already requested, do nothing. */ |
||||
|
if (self->state != NN_FSM_STATE_ACTIVE) |
||||
|
return; |
||||
|
|
||||
|
self->state = NN_FSM_STATE_STOPPING; |
||||
|
self->shutdown_fn (self, NN_FSM_ACTION, NN_FSM_STOP, NULL); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_stopped (struct nn_fsm *self, int type) |
||||
|
{ |
||||
|
nn_assert_state (self, NN_FSM_STATE_STOPPING); |
||||
|
nn_fsm_raise (self, &self->stopped, type); |
||||
|
self->state = NN_FSM_STATE_IDLE; |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_stopped_noevent (struct nn_fsm *self) |
||||
|
{ |
||||
|
nn_assert_state (self, NN_FSM_STATE_STOPPING); |
||||
|
self->state = NN_FSM_STATE_IDLE; |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_swap_owner (struct nn_fsm *self, struct nn_fsm_owner *owner) |
||||
|
{ |
||||
|
int oldsrc; |
||||
|
struct nn_fsm *oldowner; |
||||
|
|
||||
|
oldsrc = self->src; |
||||
|
oldowner = self->owner; |
||||
|
self->src = owner->src; |
||||
|
self->owner = owner->fsm; |
||||
|
owner->src = oldsrc; |
||||
|
owner->fsm = oldowner; |
||||
|
} |
||||
|
|
||||
|
struct nn_worker *nn_fsm_choose_worker (struct nn_fsm *self) |
||||
|
{ |
||||
|
return nn_ctx_choose_worker (self->ctx); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_action (struct nn_fsm *self, int type) |
||||
|
{ |
||||
|
nn_assert (type > 0); |
||||
|
nn_fsm_feed (self, NN_FSM_ACTION, type, NULL); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_raise (struct nn_fsm *self, struct nn_fsm_event *event, int type) |
||||
|
{ |
||||
|
event->fsm = self->owner; |
||||
|
event->src = self->src; |
||||
|
event->srcptr = self->srcptr; |
||||
|
event->type = type; |
||||
|
nn_ctx_raise (self->ctx, event); |
||||
|
} |
||||
|
|
||||
|
void nn_fsm_raiseto (struct nn_fsm *self, struct nn_fsm *dst, |
||||
|
struct nn_fsm_event *event, int src, int type, void *srcptr) |
||||
|
{ |
||||
|
event->fsm = dst; |
||||
|
event->src = src; |
||||
|
event->srcptr = srcptr; |
||||
|
event->type = type; |
||||
|
nn_ctx_raiseto (self->ctx, event); |
||||
|
} |
||||
|
|
@ -0,0 +1,117 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_FSM_INCLUDED |
||||
|
#define NN_FSM_INCLUDED |
||||
|
|
||||
|
#include "../utils/queue.h" |
||||
|
|
||||
|
/* Base class for state machines. */ |
||||
|
|
||||
|
struct nn_ctx; |
||||
|
struct nn_fsm; |
||||
|
struct nn_worker; |
||||
|
|
||||
|
struct nn_fsm_event { |
||||
|
struct nn_fsm *fsm; |
||||
|
int src; |
||||
|
void *srcptr; |
||||
|
int type; |
||||
|
struct nn_queue_item item; |
||||
|
}; |
||||
|
|
||||
|
void nn_fsm_event_init (struct nn_fsm_event *self); |
||||
|
void nn_fsm_event_term (struct nn_fsm_event *self); |
||||
|
int nn_fsm_event_active (struct nn_fsm_event *self); |
||||
|
void nn_fsm_event_process (struct nn_fsm_event *self); |
||||
|
|
||||
|
/* Special source for actions. It's negative not to clash with user-defined
|
||||
|
sources. */ |
||||
|
#define NN_FSM_ACTION -2 |
||||
|
|
||||
|
/* Actions generated by fsm object. The values are negative not to clash
|
||||
|
with user-defined actions. */ |
||||
|
#define NN_FSM_START -2 |
||||
|
#define NN_FSM_STOP -3 |
||||
|
|
||||
|
/* Virtual function to be implemented by the derived class to handle the
|
||||
|
incoming events. */ |
||||
|
typedef void (*nn_fsm_fn) (struct nn_fsm *self, int src, int type, |
||||
|
void *srcptr); |
||||
|
|
||||
|
struct nn_fsm_owner { |
||||
|
int src; |
||||
|
struct nn_fsm *fsm; |
||||
|
}; |
||||
|
|
||||
|
struct nn_fsm { |
||||
|
nn_fsm_fn fn; |
||||
|
nn_fsm_fn shutdown_fn; |
||||
|
int state; |
||||
|
int src; |
||||
|
void *srcptr; |
||||
|
struct nn_fsm *owner; |
||||
|
struct nn_ctx *ctx; |
||||
|
struct nn_fsm_event stopped; |
||||
|
}; |
||||
|
|
||||
|
void nn_fsm_init_root (struct nn_fsm *self, nn_fsm_fn fn, |
||||
|
nn_fsm_fn shutdown_fn, struct nn_ctx *ctx); |
||||
|
void nn_fsm_init (struct nn_fsm *self, nn_fsm_fn fn, |
||||
|
nn_fsm_fn shutdown_fn, |
||||
|
int src, void *srcptr, struct nn_fsm *owner); |
||||
|
void nn_fsm_term (struct nn_fsm *self); |
||||
|
|
||||
|
int nn_fsm_isidle (struct nn_fsm *self); |
||||
|
void nn_fsm_start (struct nn_fsm *self); |
||||
|
void nn_fsm_stop (struct nn_fsm *self); |
||||
|
void nn_fsm_stopped (struct nn_fsm *self, int type); |
||||
|
void nn_fsm_stopped_noevent (struct nn_fsm *self); |
||||
|
|
||||
|
/* Replaces current owner of the fsm by the owner speicified by 'owner'
|
||||
|
parameter. The parameter will hold the old owner afrer the call. */ |
||||
|
void nn_fsm_swap_owner (struct nn_fsm *self, struct nn_fsm_owner *owner); |
||||
|
|
||||
|
struct nn_worker *nn_fsm_choose_worker (struct nn_fsm *self); |
||||
|
|
||||
|
/* Using this function state machine can trigger an action on itself. */ |
||||
|
void nn_fsm_action (struct nn_fsm *self, int type); |
||||
|
|
||||
|
/* Send event from the state machine to its owner. */ |
||||
|
void nn_fsm_raise (struct nn_fsm *self, struct nn_fsm_event *event, int type); |
||||
|
|
||||
|
|
||||
|
/* Send event to the specified state machine. It's caller's responsibility
|
||||
|
to ensure that the destination state machine will still exist when the |
||||
|
event is delivered. |
||||
|
NOTE: This function is a hack to make inproc transport work in the most |
||||
|
efficient manner. Do not use it outside of inproc transport! */ |
||||
|
void nn_fsm_raiseto (struct nn_fsm *self, struct nn_fsm *dst, |
||||
|
struct nn_fsm_event *event, int src, int type, void *srcptr); |
||||
|
|
||||
|
/* This function is very lowlevel action feeding
|
||||
|
Used in worker threads and timers, shouldn't be used by others |
||||
|
use nn_fsm_action/nn_fsm_raise/nn_fsm_raiseto instread*/ |
||||
|
void nn_fsm_feed (struct nn_fsm *self, int src, int type, void *srcptr); |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,35 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "poller.h" |
||||
|
|
||||
|
#if !defined NN_HAVE_WINDOWS |
||||
|
|
||||
|
#if defined NN_USE_POLL |
||||
|
#include "poller_poll.c" |
||||
|
#elif defined NN_USE_EPOLL |
||||
|
xxx #include "poller_epoll.c" |
||||
|
#elif defined NN_USE_KQUEUE |
||||
|
xxx #include "poller_kqueue.c" |
||||
|
#endif |
||||
|
|
||||
|
#endif |
@ -0,0 +1,58 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_POLLER_INCLUDED |
||||
|
#define NN_POLLER_INCLUDED |
||||
|
|
||||
|
#include "../nn_config.h" |
||||
|
|
||||
|
#if !defined NN_HAVE_WINDOWS |
||||
|
|
||||
|
#define NN_POLLER_IN 1 |
||||
|
#define NN_POLLER_OUT 2 |
||||
|
#define NN_POLLER_ERR 3 |
||||
|
|
||||
|
#if defined NN_USE_POLL |
||||
|
#include "poller_poll.h" |
||||
|
#elif defined NN_USE_EPOLL |
||||
|
xxx #include "poller_epoll.h" |
||||
|
#elif defined NN_USE_KQUEUE |
||||
|
xx #include "poller_kqueue.h" |
||||
|
#endif |
||||
|
|
||||
|
int nn_poller_init (struct nn_poller *self); |
||||
|
void nn_poller_term (struct nn_poller *self); |
||||
|
void nn_poller_add (struct nn_poller *self, int fd, |
||||
|
struct nn_poller_hndl *hndl); |
||||
|
void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl); |
||||
|
void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl); |
||||
|
void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl); |
||||
|
void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl); |
||||
|
void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl); |
||||
|
int nn_poller_wait (struct nn_poller *self, int timeout); |
||||
|
int nn_poller_event (struct nn_poller *self, int *event, |
||||
|
struct nn_poller_hndl **hndl); |
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,229 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../utils/fast.h" |
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/closefd.h" |
||||
|
|
||||
|
#include <string.h> |
||||
|
#include <unistd.h> |
||||
|
#include <fcntl.h> |
||||
|
|
||||
|
int nn_poller_init (struct nn_poller *self) |
||||
|
{ |
||||
|
#ifndef EPOLL_CLOEXEC |
||||
|
int rc; |
||||
|
#endif |
||||
|
|
||||
|
#ifdef EPOLL_CLOEXEC |
||||
|
self->ep = epoll_create1 (EPOLL_CLOEXEC); |
||||
|
#else |
||||
|
/* Size parameter is unused, we can safely set it to 1. */ |
||||
|
self->ep = epoll_create (1); |
||||
|
rc = fcntl (self->ep, F_SETFD, FD_CLOEXEC); |
||||
|
errno_assert (rc != -1); |
||||
|
#endif |
||||
|
if (self->ep == -1) { |
||||
|
if (errno == ENFILE || errno == EMFILE) |
||||
|
return -EMFILE; |
||||
|
errno_assert (0); |
||||
|
} |
||||
|
self->nevents = 0; |
||||
|
self->index = 0; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_term (struct nn_poller *self) |
||||
|
{ |
||||
|
nn_closefd (self->ep); |
||||
|
} |
||||
|
|
||||
|
void nn_poller_add (struct nn_poller *self, int fd, |
||||
|
struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct epoll_event ev; |
||||
|
|
||||
|
/* Initialise the handle and add the file descriptor to the pollset. */ |
||||
|
hndl->fd = fd; |
||||
|
hndl->events = 0; |
||||
|
memset (&ev, 0, sizeof (ev)); |
||||
|
ev.events = 0; |
||||
|
ev.data.ptr = (void*) hndl; |
||||
|
rc = epoll_ctl (self->ep, EPOLL_CTL_ADD, fd, &ev); |
||||
|
errno_assert (rc == 0); |
||||
|
} |
||||
|
|
||||
|
void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
int i; |
||||
|
|
||||
|
/* Remove the file descriptor from the pollset. */ |
||||
|
rc = epoll_ctl (self->ep, EPOLL_CTL_DEL, hndl->fd, NULL); |
||||
|
errno_assert (rc == 0); |
||||
|
|
||||
|
/* Invalidate any subsequent events on this file descriptor. */ |
||||
|
for (i = self->index; i != self->nevents; ++i) |
||||
|
if (self->events [i].data.ptr == hndl) |
||||
|
self->events [i].events = 0; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct epoll_event ev; |
||||
|
|
||||
|
/* If already polling for IN, do nothing. */ |
||||
|
if (nn_slow (hndl->events & EPOLLIN)) |
||||
|
return; |
||||
|
|
||||
|
/* Start polling for IN. */ |
||||
|
hndl->events |= EPOLLIN; |
||||
|
memset (&ev, 0, sizeof (ev)); |
||||
|
ev.events = hndl->events; |
||||
|
ev.data.ptr = (void*) hndl; |
||||
|
rc = epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev); |
||||
|
errno_assert (rc == 0); |
||||
|
} |
||||
|
|
||||
|
void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
int i; |
||||
|
struct epoll_event ev; |
||||
|
|
||||
|
/* If not polling for IN, do nothing. */ |
||||
|
if (nn_slow (!(hndl->events & EPOLLIN))) |
||||
|
return; |
||||
|
|
||||
|
/* Stop polling for IN. */ |
||||
|
hndl->events &= ~EPOLLIN; |
||||
|
memset (&ev, 0, sizeof (ev)); |
||||
|
ev.events = hndl->events; |
||||
|
ev.data.ptr = (void*) hndl; |
||||
|
rc = epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev); |
||||
|
errno_assert (rc == 0); |
||||
|
|
||||
|
/* Invalidate any subsequent IN events on this file descriptor. */ |
||||
|
for (i = self->index; i != self->nevents; ++i) |
||||
|
if (self->events [i].data.ptr == hndl) |
||||
|
self->events [i].events &= ~EPOLLIN; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct epoll_event ev; |
||||
|
|
||||
|
/* If already polling for OUT, do nothing. */ |
||||
|
if (nn_slow (hndl->events & EPOLLOUT)) |
||||
|
return; |
||||
|
|
||||
|
/* Start polling for OUT. */ |
||||
|
hndl->events |= EPOLLOUT; |
||||
|
memset (&ev, 0, sizeof (ev)); |
||||
|
ev.events = hndl->events; |
||||
|
ev.data.ptr = (void*) hndl; |
||||
|
rc = epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev); |
||||
|
errno_assert (rc == 0); |
||||
|
} |
||||
|
|
||||
|
void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
int i; |
||||
|
struct epoll_event ev; |
||||
|
|
||||
|
/* If not polling for OUT, do nothing. */ |
||||
|
if (nn_slow (!(hndl->events & EPOLLOUT))) |
||||
|
return; |
||||
|
|
||||
|
/* Stop polling for OUT. */ |
||||
|
hndl->events &= ~EPOLLOUT; |
||||
|
memset (&ev, 0, sizeof (ev)); |
||||
|
ev.events = hndl->events; |
||||
|
ev.data.ptr = (void*) hndl; |
||||
|
rc = epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev); |
||||
|
errno_assert (rc == 0); |
||||
|
|
||||
|
/* Invalidate any subsequent OUT events on this file descriptor. */ |
||||
|
for (i = self->index; i != self->nevents; ++i) |
||||
|
if (self->events [i].data.ptr == hndl) |
||||
|
self->events [i].events &= ~EPOLLOUT; |
||||
|
} |
||||
|
|
||||
|
int nn_poller_wait (struct nn_poller *self, int timeout) |
||||
|
{ |
||||
|
int nevents; |
||||
|
|
||||
|
/* Clear all existing events. */ |
||||
|
self->nevents = 0; |
||||
|
self->index = 0; |
||||
|
|
||||
|
/* Wait for new events. */ |
||||
|
while (1) { |
||||
|
nevents = epoll_wait (self->ep, self->events, |
||||
|
NN_POLLER_MAX_EVENTS, timeout); |
||||
|
if (nn_slow (nevents == -1 && errno == EINTR)) |
||||
|
continue; |
||||
|
break; |
||||
|
} |
||||
|
errno_assert (self->nevents != -1); |
||||
|
self->nevents = nevents; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int nn_poller_event (struct nn_poller *self, int *event, |
||||
|
struct nn_poller_hndl **hndl) |
||||
|
{ |
||||
|
/* Skip over empty events. */ |
||||
|
while (self->index < self->nevents) { |
||||
|
if (self->events [self->index].events != 0) |
||||
|
break; |
||||
|
++self->index; |
||||
|
} |
||||
|
|
||||
|
/* If there is no stored event, let the caller know. */ |
||||
|
if (nn_slow (self->index >= self->nevents)) |
||||
|
return -EAGAIN; |
||||
|
|
||||
|
/* Return next event to the caller. Remove the event from the set. */ |
||||
|
*hndl = (struct nn_poller_hndl*) self->events [self->index].data.ptr; |
||||
|
if (nn_fast (self->events [self->index].events & EPOLLIN)) { |
||||
|
*event = NN_POLLER_IN; |
||||
|
self->events [self->index].events &= ~EPOLLIN; |
||||
|
return 0; |
||||
|
} |
||||
|
else if (nn_fast (self->events [self->index].events & EPOLLOUT)) { |
||||
|
*event = NN_POLLER_OUT; |
||||
|
self->events [self->index].events &= ~EPOLLOUT; |
||||
|
return 0; |
||||
|
} |
||||
|
else { |
||||
|
*event = NN_POLLER_ERR; |
||||
|
++self->index; |
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,53 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#define NN_USE_POLL |
||||
|
|
||||
|
|
||||
|
#include <stdint.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/epoll.h> |
||||
|
|
||||
|
#define NN_POLLER_HAVE_ASYNC_ADD 1 |
||||
|
|
||||
|
#define NN_POLLER_MAX_EVENTS 32 |
||||
|
|
||||
|
struct nn_poller_hndl { |
||||
|
int fd; |
||||
|
uint32_t events; |
||||
|
}; |
||||
|
|
||||
|
struct nn_poller { |
||||
|
|
||||
|
/* Current pollset. */ |
||||
|
int ep; |
||||
|
|
||||
|
/* Number of events being processed at the moment. */ |
||||
|
int nevents; |
||||
|
|
||||
|
/* Index of the event being processed at the moment. */ |
||||
|
int index; |
||||
|
|
||||
|
/* Events being processed at the moment. */ |
||||
|
struct epoll_event events [NN_POLLER_MAX_EVENTS]; |
||||
|
}; |
||||
|
|
@ -0,0 +1,212 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../utils/fast.h" |
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/closefd.h" |
||||
|
|
||||
|
#include <unistd.h> |
||||
|
|
||||
|
/* NetBSD has different definition of udata. */ |
||||
|
#if defined NN_HAVE_NETBSD |
||||
|
#define nn_poller_udata intptr_t |
||||
|
#else |
||||
|
#define nn_poller_udata void* |
||||
|
#endif |
||||
|
|
||||
|
int nn_poller_init (struct nn_poller *self) |
||||
|
{ |
||||
|
self->kq = kqueue (); |
||||
|
if (self->kq == -1) { |
||||
|
if (errno == ENFILE || errno == EMFILE) |
||||
|
return -EMFILE; |
||||
|
errno_assert (0); |
||||
|
} |
||||
|
self->nevents = 0; |
||||
|
self->index = 0; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_term (struct nn_poller *self) |
||||
|
{ |
||||
|
nn_closefd (self->kq); |
||||
|
} |
||||
|
|
||||
|
void nn_poller_add (struct nn_poller *self, int fd, |
||||
|
struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
/* Initialise the handle. */ |
||||
|
hndl->fd = fd; |
||||
|
hndl->events = 0; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct kevent ev; |
||||
|
int i; |
||||
|
|
||||
|
if (hndl->events & NN_POLLER_EVENT_IN) { |
||||
|
EV_SET (&ev, hndl->fd, EVFILT_READ, EV_DELETE, 0, 0, 0); |
||||
|
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); |
||||
|
errno_assert (rc != -1); |
||||
|
} |
||||
|
|
||||
|
if (hndl->events & NN_POLLER_EVENT_OUT) { |
||||
|
EV_SET (&ev, hndl->fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); |
||||
|
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); |
||||
|
errno_assert (rc != -1); |
||||
|
} |
||||
|
|
||||
|
/* Invalidate any subsequent events on this file descriptor. */ |
||||
|
for (i = self->index; i != self->nevents; ++i) |
||||
|
if (self->events [i].ident == (unsigned) hndl->fd) |
||||
|
self->events [i].udata = (nn_poller_udata) NULL; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct kevent ev; |
||||
|
|
||||
|
if (!(hndl->events & NN_POLLER_EVENT_IN)) { |
||||
|
EV_SET (&ev, hndl->fd, EVFILT_READ, EV_ADD, 0, 0, |
||||
|
(nn_poller_udata) hndl); |
||||
|
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); |
||||
|
errno_assert (rc != -1); |
||||
|
hndl->events |= NN_POLLER_EVENT_IN; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct kevent ev; |
||||
|
int i; |
||||
|
|
||||
|
if (hndl->events & NN_POLLER_EVENT_IN) { |
||||
|
EV_SET (&ev, hndl->fd, EVFILT_READ, EV_DELETE, 0, 0, 0); |
||||
|
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); |
||||
|
errno_assert (rc != -1); |
||||
|
hndl->events &= ~NN_POLLER_EVENT_IN; |
||||
|
} |
||||
|
|
||||
|
/* Invalidate any subsequent IN events on this file descriptor. */ |
||||
|
for (i = self->index; i != self->nevents; ++i) |
||||
|
if (self->events [i].ident == (unsigned) hndl->fd && |
||||
|
self->events [i].filter == EVFILT_READ) |
||||
|
self->events [i].udata = (nn_poller_udata) NULL; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct kevent ev; |
||||
|
|
||||
|
if (!(hndl->events & NN_POLLER_EVENT_OUT)) { |
||||
|
EV_SET (&ev, hndl->fd, EVFILT_WRITE, EV_ADD, 0, 0, |
||||
|
(nn_poller_udata) hndl); |
||||
|
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); |
||||
|
errno_assert (rc != -1); |
||||
|
hndl->events |= NN_POLLER_EVENT_OUT; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct kevent ev; |
||||
|
int i; |
||||
|
|
||||
|
if (hndl->events & NN_POLLER_EVENT_OUT) { |
||||
|
EV_SET (&ev, hndl->fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); |
||||
|
rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); |
||||
|
errno_assert (rc != -1); |
||||
|
hndl->events &= ~NN_POLLER_EVENT_OUT; |
||||
|
} |
||||
|
|
||||
|
/* Invalidate any subsequent OUT events on this file descriptor. */ |
||||
|
for (i = self->index; i != self->nevents; ++i) |
||||
|
if (self->events [i].ident == (unsigned) hndl->fd && |
||||
|
self->events [i].filter == EVFILT_WRITE) |
||||
|
self->events [i].udata = (nn_poller_udata) NULL; |
||||
|
} |
||||
|
|
||||
|
int nn_poller_wait (struct nn_poller *self, int timeout) |
||||
|
{ |
||||
|
struct timespec ts; |
||||
|
int nevents; |
||||
|
|
||||
|
/* Clear all existing events. */ |
||||
|
self->nevents = 0; |
||||
|
self->index = 0; |
||||
|
|
||||
|
/* Wait for new events. */ |
||||
|
#if defined NN_IGNORE_EINTR |
||||
|
again: |
||||
|
#endif |
||||
|
ts.tv_sec = timeout / 1000; |
||||
|
ts.tv_nsec = (timeout % 1000) * 1000000; |
||||
|
nevents = kevent (self->kq, NULL, 0, &self->events [0], |
||||
|
NN_POLLER_MAX_EVENTS, timeout >= 0 ? &ts : NULL); |
||||
|
if (nevents == -1 && errno == EINTR) |
||||
|
#if defined NN_IGNORE_EINTR |
||||
|
goto again; |
||||
|
#else |
||||
|
return -EINTR; |
||||
|
#endif |
||||
|
errno_assert (nevents != -1); |
||||
|
|
||||
|
self->nevents = nevents; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int nn_poller_event (struct nn_poller *self, int *event, |
||||
|
struct nn_poller_hndl **hndl) |
||||
|
{ |
||||
|
/* Skip over empty events. */ |
||||
|
while (self->index < self->nevents) { |
||||
|
if (self->events [self->index].udata) |
||||
|
break; |
||||
|
++self->index; |
||||
|
} |
||||
|
|
||||
|
/* If there is no stored event, let the caller know. */ |
||||
|
if (nn_slow (self->index >= self->nevents)) |
||||
|
return -EAGAIN; |
||||
|
|
||||
|
/* Return next event to the caller. Remove the event from the set. */ |
||||
|
*hndl = (struct nn_poller_hndl*) self->events [self->index].udata; |
||||
|
if (self->events [self->index].flags & EV_EOF) |
||||
|
*event = NN_POLLER_ERR; |
||||
|
else if (self->events [self->index].filter == EVFILT_WRITE) |
||||
|
*event = NN_POLLER_OUT; |
||||
|
else if (self->events [self->index].filter == EVFILT_READ) |
||||
|
*event = NN_POLLER_IN; |
||||
|
else |
||||
|
nn_assert (0); |
||||
|
++self->index; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
@ -0,0 +1,51 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include <sys/time.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/event.h> |
||||
|
|
||||
|
#define NN_POLLER_MAX_EVENTS 32 |
||||
|
|
||||
|
#define NN_POLLER_EVENT_IN 1 |
||||
|
#define NN_POLLER_EVENT_OUT 2 |
||||
|
|
||||
|
struct nn_poller_hndl { |
||||
|
int fd; |
||||
|
int events; |
||||
|
}; |
||||
|
|
||||
|
struct nn_poller { |
||||
|
|
||||
|
/* Current pollset. */ |
||||
|
int kq; |
||||
|
|
||||
|
/* Number of events being processed at the moment. */ |
||||
|
int nevents; |
||||
|
|
||||
|
/* Index of the event being processed at the moment. */ |
||||
|
int index; |
||||
|
|
||||
|
/* Cached events. */ |
||||
|
struct kevent events [NN_POLLER_MAX_EVENTS]; |
||||
|
}; |
||||
|
|
@ -0,0 +1,200 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../utils/alloc.h" |
||||
|
#include "../utils/err.h" |
||||
|
|
||||
|
#define NN_POLLER_GRANULARITY 16 |
||||
|
|
||||
|
int nn_poller_init (struct nn_poller *self) |
||||
|
{ |
||||
|
self->size = 0; |
||||
|
self->index = 0; |
||||
|
self->capacity = NN_POLLER_GRANULARITY; |
||||
|
self->pollset = |
||||
|
nn_alloc (sizeof (struct pollfd) * NN_POLLER_GRANULARITY, |
||||
|
"pollset"); |
||||
|
alloc_assert (self->pollset); |
||||
|
self->hndls = |
||||
|
nn_alloc (sizeof (struct nn_hndls_item) * NN_POLLER_GRANULARITY, |
||||
|
"hndlset"); |
||||
|
alloc_assert (self->hndls); |
||||
|
self->removed = -1; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_term (struct nn_poller *self) |
||||
|
{ |
||||
|
nn_free (self->pollset); |
||||
|
nn_free (self->hndls); |
||||
|
} |
||||
|
|
||||
|
void nn_poller_add (struct nn_poller *self, int fd, |
||||
|
struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
//int rc;
|
||||
|
|
||||
|
/* If the capacity is too low to accommodate the next item, resize it. */ |
||||
|
if (nn_slow (self->size >= self->capacity)) { |
||||
|
self->capacity *= 2; |
||||
|
self->pollset = nn_realloc (self->pollset, |
||||
|
sizeof (struct pollfd) * self->capacity); |
||||
|
alloc_assert (self->pollset); |
||||
|
self->hndls = nn_realloc (self->hndls, |
||||
|
sizeof (struct nn_hndls_item) * self->capacity); |
||||
|
alloc_assert (self->hndls); |
||||
|
} |
||||
|
|
||||
|
/* Add the fd to the pollset. */ |
||||
|
self->pollset [self->size].fd = fd; |
||||
|
self->pollset [self->size].events = 0; |
||||
|
self->pollset [self->size].revents = 0; |
||||
|
hndl->index = self->size; |
||||
|
self->hndls [self->size].hndl = hndl; |
||||
|
++self->size; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
/* No more events will be reported on this fd. */ |
||||
|
self->pollset [hndl->index].revents = 0; |
||||
|
|
||||
|
/* Add the fd into the list of removed fds. */ |
||||
|
if (self->removed != -1) |
||||
|
self->hndls [self->removed].prev = hndl->index; |
||||
|
self->hndls [hndl->index].hndl = NULL; |
||||
|
self->hndls [hndl->index].prev = -1; |
||||
|
self->hndls [hndl->index].next = self->removed; |
||||
|
self->removed = hndl->index; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
self->pollset [hndl->index].events |= POLLIN; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
self->pollset [hndl->index].events &= ~POLLIN; |
||||
|
self->pollset [hndl->index].revents &= ~POLLIN; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
self->pollset [hndl->index].events |= POLLOUT; |
||||
|
} |
||||
|
|
||||
|
void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl) |
||||
|
{ |
||||
|
self->pollset [hndl->index].events &= ~POLLOUT; |
||||
|
self->pollset [hndl->index].revents &= ~POLLOUT; |
||||
|
} |
||||
|
|
||||
|
int nn_poller_wait (struct nn_poller *self, int timeout) |
||||
|
{ |
||||
|
int rc; |
||||
|
int i; |
||||
|
|
||||
|
/* First, get rid of removed fds. */ |
||||
|
while (self->removed != -1) { |
||||
|
|
||||
|
/* Remove the fd from the list of removed fds. */ |
||||
|
i = self->removed; |
||||
|
self->removed = self->hndls [i].next; |
||||
|
|
||||
|
/* Replace the removed fd by the one at the end of the pollset. */ |
||||
|
--self->size; |
||||
|
if (i != self->size) { |
||||
|
self->pollset [i] = self->pollset [self->size]; |
||||
|
if (self->hndls [i].next != -1) |
||||
|
self->hndls [self->hndls [i].next].prev = -1; |
||||
|
self->hndls [i] = self->hndls [self->size]; |
||||
|
if (self->hndls [i].hndl) |
||||
|
self->hndls [i].hndl->index = i; |
||||
|
} |
||||
|
|
||||
|
/* The fd from the end of the pollset may have been on removed fds
|
||||
|
list itself. If so, adjust the removed list. */ |
||||
|
if (nn_slow (!self->hndls [i].hndl)) { |
||||
|
if (self->hndls [i].prev != -1) |
||||
|
self->hndls [self->hndls [i].prev].next = i; |
||||
|
if (self->hndls [i].next != -1) |
||||
|
self->hndls [self->hndls [i].next].prev = i; |
||||
|
if (self->removed == self->size) |
||||
|
self->removed = i; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
self->index = 0; |
||||
|
|
||||
|
/* Wait for new events. */ |
||||
|
#if defined NN_IGNORE_EINTR |
||||
|
again: |
||||
|
#endif |
||||
|
rc = poll (self->pollset, self->size, timeout); |
||||
|
if (nn_slow (rc < 0 && errno == EINTR)) |
||||
|
#if defined NN_IGNORE_EINTR |
||||
|
goto again; |
||||
|
#else |
||||
|
return -EINTR; |
||||
|
#endif |
||||
|
errno_assert (rc >= 0); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int nn_poller_event (struct nn_poller *self, int *event, |
||||
|
struct nn_poller_hndl **hndl) |
||||
|
{ |
||||
|
//int rc;
|
||||
|
|
||||
|
/* Skip over empty events. This will also skip over removed fds as they
|
||||
|
have their revents nullified. */ |
||||
|
while (self->index < self->size) { |
||||
|
if (self->pollset [self->index].revents != 0) |
||||
|
break; |
||||
|
++self->index; |
||||
|
} |
||||
|
|
||||
|
/* If there is no available event, let the caller know. */ |
||||
|
if (nn_slow (self->index >= self->size)) |
||||
|
return -EAGAIN; |
||||
|
|
||||
|
/* Return next event to the caller. Remove the event from revents. */ |
||||
|
*hndl = self->hndls [self->index].hndl; |
||||
|
if (nn_fast (self->pollset [self->index].revents & POLLIN)) { |
||||
|
*event = NN_POLLER_IN; |
||||
|
self->pollset [self->index].revents &= ~POLLIN; |
||||
|
return 0; |
||||
|
} |
||||
|
else if (nn_fast (self->pollset [self->index].revents & POLLOUT)) { |
||||
|
*event = NN_POLLER_OUT; |
||||
|
self->pollset [self->index].revents &= ~POLLOUT; |
||||
|
return 0; |
||||
|
} |
||||
|
else { |
||||
|
*event = NN_POLLER_ERR; |
||||
|
++self->index; |
||||
|
return 0; |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,57 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include <poll.h> |
||||
|
|
||||
|
#define NN_POLLER_HAVE_ASYNC_ADD 0 |
||||
|
|
||||
|
struct nn_poller_hndl { |
||||
|
int index; |
||||
|
}; |
||||
|
|
||||
|
struct nn_poller { |
||||
|
|
||||
|
/* Actual number of elements in the pollset. */ |
||||
|
int size; |
||||
|
|
||||
|
/* Index of the event being processed at the moment. */ |
||||
|
int index; |
||||
|
|
||||
|
/* Number of allocated elements in the pollset. */ |
||||
|
int capacity; |
||||
|
|
||||
|
/* The pollset. */ |
||||
|
struct pollfd *pollset; |
||||
|
|
||||
|
/* List of handles associated with elements in the pollset. Either points
|
||||
|
to the handle associated with the file descriptor (hndl) or is part |
||||
|
of the list of removed pollitems (removed). */ |
||||
|
struct nn_hndls_item { |
||||
|
struct nn_poller_hndl *hndl; |
||||
|
int prev; |
||||
|
int next; |
||||
|
} *hndls; |
||||
|
|
||||
|
/* List of removed pollitems, linked by indices. -1 means empty list. */ |
||||
|
int removed; |
||||
|
}; |
||||
|
|
@ -0,0 +1,40 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "pool.h" |
||||
|
|
||||
|
// TODO: The dummy implementation of a thread pool. As for now there's only one worker thread created.
|
||||
|
|
||||
|
int nn_pool_init(struct nn_pool *self) |
||||
|
{ |
||||
|
return nn_worker_init(&self->worker); |
||||
|
} |
||||
|
|
||||
|
void nn_pool_term (struct nn_pool *self) |
||||
|
{ |
||||
|
nn_worker_term(&self->worker); |
||||
|
} |
||||
|
|
||||
|
struct nn_worker *nn_pool_choose_worker (struct nn_pool *self) |
||||
|
{ |
||||
|
return &self->worker; |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_POOL_INCLUDED |
||||
|
#define NN_POOL_INCLUDED |
||||
|
|
||||
|
#include "worker.h" |
||||
|
|
||||
|
/* Worker thread pool. */ |
||||
|
|
||||
|
struct nn_pool { struct nn_worker worker; }; |
||||
|
|
||||
|
int nn_pool_init(struct nn_pool *self); |
||||
|
void nn_pool_term(struct nn_pool *self); |
||||
|
struct nn_worker *nn_pool_choose_worker (struct nn_pool *self); |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,178 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "timer.h" |
||||
|
|
||||
|
#include "../utils/cont.h" |
||||
|
#include "../utils/fast.h" |
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/attr.h" |
||||
|
|
||||
|
/* Timer state reflects the state as seen by the user thread. It says nothing
|
||||
|
about the state of affairs in the worker thread. */ |
||||
|
#define NN_TIMER_STATE_IDLE 1 |
||||
|
#define NN_TIMER_STATE_ACTIVE 2 |
||||
|
#define NN_TIMER_STATE_STOPPING 3 |
||||
|
|
||||
|
#define NN_TIMER_SRC_START_TASK 1 |
||||
|
#define NN_TIMER_SRC_STOP_TASK 2 |
||||
|
|
||||
|
/* Private functions. */ |
||||
|
static void nn_timer_handler (struct nn_fsm *self, int src, int type, |
||||
|
void *srcptr); |
||||
|
static void nn_timer_shutdown (struct nn_fsm *self, int src, int type, |
||||
|
void *srcptr); |
||||
|
|
||||
|
void nn_timer_init (struct nn_timer *self, int src, struct nn_fsm *owner) |
||||
|
{ |
||||
|
nn_fsm_init (&self->fsm, nn_timer_handler, nn_timer_shutdown, |
||||
|
src, self, owner); |
||||
|
self->state = NN_TIMER_STATE_IDLE; |
||||
|
nn_worker_task_init (&self->start_task, NN_TIMER_SRC_START_TASK, |
||||
|
&self->fsm); |
||||
|
nn_worker_task_init (&self->stop_task, NN_TIMER_SRC_STOP_TASK, &self->fsm); |
||||
|
nn_worker_timer_init (&self->wtimer, &self->fsm); |
||||
|
nn_fsm_event_init (&self->done); |
||||
|
self->worker = nn_fsm_choose_worker (&self->fsm); |
||||
|
self->timeout = -1; |
||||
|
} |
||||
|
|
||||
|
void nn_timer_term (struct nn_timer *self) |
||||
|
{ |
||||
|
nn_assert_state (self, NN_TIMER_STATE_IDLE); |
||||
|
|
||||
|
nn_fsm_event_term (&self->done); |
||||
|
nn_worker_timer_term (&self->wtimer); |
||||
|
nn_worker_task_term (&self->stop_task); |
||||
|
nn_worker_task_term (&self->start_task); |
||||
|
nn_fsm_term (&self->fsm); |
||||
|
} |
||||
|
|
||||
|
int nn_timer_isidle (struct nn_timer *self) |
||||
|
{ |
||||
|
return nn_fsm_isidle (&self->fsm); |
||||
|
} |
||||
|
|
||||
|
void nn_timer_start (struct nn_timer *self, int timeout) |
||||
|
{ |
||||
|
/* Negative timeout make no sense. */ |
||||
|
nn_assert (timeout >= 0); |
||||
|
|
||||
|
self->timeout = timeout; |
||||
|
nn_fsm_start (&self->fsm); |
||||
|
} |
||||
|
|
||||
|
void nn_timer_stop (struct nn_timer *self) |
||||
|
{ |
||||
|
nn_fsm_stop (&self->fsm); |
||||
|
} |
||||
|
|
||||
|
static void nn_timer_shutdown (struct nn_fsm *self, int src, int type, |
||||
|
NN_UNUSED void *srcptr) |
||||
|
{ |
||||
|
struct nn_timer *timer; |
||||
|
|
||||
|
timer = nn_cont (self, struct nn_timer, fsm); |
||||
|
|
||||
|
if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { |
||||
|
timer->state = NN_TIMER_STATE_STOPPING; |
||||
|
nn_worker_execute (timer->worker, &timer->stop_task); |
||||
|
return; |
||||
|
} |
||||
|
if (nn_slow (timer->state == NN_TIMER_STATE_STOPPING)) { |
||||
|
if (src != NN_TIMER_SRC_STOP_TASK) |
||||
|
return; |
||||
|
nn_assert (type == NN_WORKER_TASK_EXECUTE); |
||||
|
nn_worker_rm_timer (timer->worker, &timer->wtimer); |
||||
|
timer->state = NN_TIMER_STATE_IDLE; |
||||
|
nn_fsm_stopped (&timer->fsm, NN_TIMER_STOPPED); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
nn_fsm_bad_state(timer->state, src, type); |
||||
|
} |
||||
|
|
||||
|
static void nn_timer_handler (struct nn_fsm *self, int src, int type, |
||||
|
void *srcptr) |
||||
|
{ |
||||
|
struct nn_timer *timer; |
||||
|
|
||||
|
timer = nn_cont (self, struct nn_timer, fsm); |
||||
|
|
||||
|
switch (timer->state) { |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* IDLE state. */ |
||||
|
/******************************************************************************/ |
||||
|
case NN_TIMER_STATE_IDLE: |
||||
|
switch (src) { |
||||
|
case NN_FSM_ACTION: |
||||
|
switch (type) { |
||||
|
case NN_FSM_START: |
||||
|
|
||||
|
/* Send start event to the worker thread. */ |
||||
|
timer->state = NN_TIMER_STATE_ACTIVE; |
||||
|
nn_worker_execute (timer->worker, &timer->start_task); |
||||
|
return; |
||||
|
default: |
||||
|
nn_fsm_bad_action (timer->state, src, type); |
||||
|
} |
||||
|
default: |
||||
|
nn_fsm_bad_source (timer->state, src, type); |
||||
|
} |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* ACTIVE state. */ |
||||
|
/******************************************************************************/ |
||||
|
case NN_TIMER_STATE_ACTIVE: |
||||
|
if (src == NN_TIMER_SRC_START_TASK) { |
||||
|
nn_assert (type == NN_WORKER_TASK_EXECUTE); |
||||
|
nn_assert (timer->timeout >= 0); |
||||
|
nn_worker_add_timer (timer->worker, timer->timeout, |
||||
|
&timer->wtimer); |
||||
|
timer->timeout = -1; |
||||
|
return; |
||||
|
} |
||||
|
if (srcptr == &timer->wtimer) { |
||||
|
switch (type) { |
||||
|
case NN_WORKER_TIMER_TIMEOUT: |
||||
|
|
||||
|
/* Notify the user about the timeout. */ |
||||
|
nn_assert (timer->timeout == -1); |
||||
|
nn_fsm_raise (&timer->fsm, &timer->done, NN_TIMER_TIMEOUT); |
||||
|
return; |
||||
|
|
||||
|
default: |
||||
|
nn_fsm_bad_action (timer->state, src, type); |
||||
|
} |
||||
|
} |
||||
|
nn_fsm_bad_source (timer->state, src, type); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Invalid state. */ |
||||
|
/******************************************************************************/ |
||||
|
default: |
||||
|
nn_fsm_bad_state (timer->state, src, type); |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,50 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_TIMER_INCLUDED |
||||
|
#define NN_TIMER_INCLUDED |
||||
|
|
||||
|
#include "fsm.h" |
||||
|
#include "worker.h" |
||||
|
|
||||
|
#define NN_TIMER_TIMEOUT 1 |
||||
|
#define NN_TIMER_STOPPED 2 |
||||
|
|
||||
|
struct nn_timer { |
||||
|
struct nn_fsm fsm; |
||||
|
int state; |
||||
|
struct nn_worker_task start_task; |
||||
|
struct nn_worker_task stop_task; |
||||
|
struct nn_worker_timer wtimer; |
||||
|
struct nn_fsm_event done; |
||||
|
struct nn_worker *worker; |
||||
|
int timeout; |
||||
|
}; |
||||
|
|
||||
|
void nn_timer_init (struct nn_timer *self, int src, struct nn_fsm *owner); |
||||
|
void nn_timer_term (struct nn_timer *self); |
||||
|
|
||||
|
int nn_timer_isidle (struct nn_timer *self); |
||||
|
void nn_timer_start (struct nn_timer *self, int timeout); |
||||
|
void nn_timer_stop (struct nn_timer *self); |
||||
|
|
||||
|
#endif |
@ -0,0 +1,129 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "timerset.h" |
||||
|
|
||||
|
#include "../utils/fast.h" |
||||
|
#include "../utils/cont.h" |
||||
|
#include "../utils/err.h" |
||||
|
|
||||
|
void nn_timerset_init (struct nn_timerset *self) |
||||
|
{ |
||||
|
nn_clock_init (&self->clock); |
||||
|
nn_list_init (&self->timeouts); |
||||
|
} |
||||
|
|
||||
|
void nn_timerset_term (struct nn_timerset *self) |
||||
|
{ |
||||
|
nn_list_term (&self->timeouts); |
||||
|
nn_clock_term (&self->clock); |
||||
|
} |
||||
|
|
||||
|
int nn_timerset_add (struct nn_timerset *self, int timeout, |
||||
|
struct nn_timerset_hndl *hndl) |
||||
|
{ |
||||
|
struct nn_list_item *it; |
||||
|
struct nn_timerset_hndl *ith; |
||||
|
int first; |
||||
|
|
||||
|
/* Compute the instant when the timeout will be due. */ |
||||
|
hndl->timeout = nn_clock_now (&self->clock) + timeout; |
||||
|
|
||||
|
/* Insert it into the ordered list of timeouts. */ |
||||
|
for (it = nn_list_begin (&self->timeouts); |
||||
|
it != nn_list_end (&self->timeouts); |
||||
|
it = nn_list_next (&self->timeouts, it)) { |
||||
|
ith = nn_cont (it, struct nn_timerset_hndl, list); |
||||
|
if (hndl->timeout < ith->timeout) |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
/* If the new timeout happens to be the first one to expire, let the user
|
||||
|
know that the current waiting interval has to be changed. */ |
||||
|
first = nn_list_begin (&self->timeouts) == it ? 1 : 0; |
||||
|
nn_list_insert (&self->timeouts, &hndl->list, it); |
||||
|
return first; |
||||
|
} |
||||
|
|
||||
|
int nn_timerset_rm (struct nn_timerset *self, struct nn_timerset_hndl *hndl) |
||||
|
{ |
||||
|
int first; |
||||
|
|
||||
|
/* Ignore if handle is not in the timeouts list. */ |
||||
|
if (!nn_list_item_isinlist (&hndl->list)) |
||||
|
return 0; |
||||
|
|
||||
|
/* If it was the first timeout that was removed, the actual waiting time
|
||||
|
may have changed. We'll thus return 1 to let the user know. */ |
||||
|
first = nn_list_begin (&self->timeouts) == &hndl->list ? 1 : 0; |
||||
|
nn_list_erase (&self->timeouts, &hndl->list); |
||||
|
return first; |
||||
|
} |
||||
|
|
||||
|
int nn_timerset_timeout (struct nn_timerset *self) |
||||
|
{ |
||||
|
int timeout; |
||||
|
|
||||
|
if (nn_fast (nn_list_empty (&self->timeouts))) |
||||
|
return -1; |
||||
|
|
||||
|
timeout = (int) (nn_cont (nn_list_begin (&self->timeouts), |
||||
|
struct nn_timerset_hndl, list)->timeout - nn_clock_now (&self->clock)); |
||||
|
return timeout < 0 ? 0 : timeout; |
||||
|
} |
||||
|
|
||||
|
int nn_timerset_event (struct nn_timerset *self, struct nn_timerset_hndl **hndl) |
||||
|
{ |
||||
|
struct nn_timerset_hndl *first; |
||||
|
|
||||
|
/* If there's no timeout, there's no event to report. */ |
||||
|
if (nn_fast (nn_list_empty (&self->timeouts))) |
||||
|
return -EAGAIN; |
||||
|
|
||||
|
/* If no timeout have expired yet, there's no event to return. */ |
||||
|
first = nn_cont (nn_list_begin (&self->timeouts), |
||||
|
struct nn_timerset_hndl, list); |
||||
|
if (first->timeout > nn_clock_now (&self->clock)) |
||||
|
return -EAGAIN; |
||||
|
|
||||
|
/* Return the first timeout and remove it from the list of active
|
||||
|
timeouts. */ |
||||
|
nn_list_erase (&self->timeouts, &first->list); |
||||
|
*hndl = first; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void nn_timerset_hndl_init (struct nn_timerset_hndl *self) |
||||
|
{ |
||||
|
nn_list_item_init (&self->list); |
||||
|
} |
||||
|
|
||||
|
void nn_timerset_hndl_term (struct nn_timerset_hndl *self) |
||||
|
{ |
||||
|
nn_list_item_term (&self->list); |
||||
|
} |
||||
|
|
||||
|
int nn_timerset_hndl_isactive (struct nn_timerset_hndl *self) |
||||
|
{ |
||||
|
return nn_list_item_isinlist (&self->list); |
||||
|
} |
||||
|
|
@ -0,0 +1,55 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_TIMERSET_INCLUDED |
||||
|
#define NN_TIMERSET_INCLUDED |
||||
|
|
||||
|
#include "../utils/clock.h" |
||||
|
#include "../utils/list.h" |
||||
|
|
||||
|
/* This class stores a list of timeouts and reports the next one to expire
|
||||
|
along with the time till it happens. */ |
||||
|
|
||||
|
struct nn_timerset_hndl { |
||||
|
struct nn_list_item list; |
||||
|
uint64_t timeout; |
||||
|
}; |
||||
|
|
||||
|
struct nn_timerset { |
||||
|
struct nn_clock clock; |
||||
|
struct nn_list timeouts; |
||||
|
}; |
||||
|
|
||||
|
void nn_timerset_init (struct nn_timerset *self); |
||||
|
void nn_timerset_term (struct nn_timerset *self); |
||||
|
int nn_timerset_add (struct nn_timerset *self, int timeout, |
||||
|
struct nn_timerset_hndl *hndl); |
||||
|
int nn_timerset_rm (struct nn_timerset *self, struct nn_timerset_hndl *hndl); |
||||
|
int nn_timerset_timeout (struct nn_timerset *self); |
||||
|
int nn_timerset_event (struct nn_timerset *self, struct nn_timerset_hndl **hndl); |
||||
|
|
||||
|
void nn_timerset_hndl_init (struct nn_timerset_hndl *self); |
||||
|
void nn_timerset_hndl_term (struct nn_timerset_hndl *self); |
||||
|
int nn_timerset_hndl_isactive (struct nn_timerset_hndl *self); |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,33 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "usock.h" |
||||
|
|
||||
|
#if defined NN_HAVE_WINDOWS |
||||
|
#include "usock_win.c" |
||||
|
#else |
||||
|
#include "usock_posix.c" |
||||
|
#endif |
||||
|
|
||||
|
int nn_usock_geterrno (struct nn_usock *self) { |
||||
|
return self->errnum; |
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_USOCK_INCLUDED |
||||
|
#define NN_USOCK_INCLUDED |
||||
|
|
||||
|
/* Import the definition of nn_iovec. */ |
||||
|
#include "../nn.h" |
||||
|
|
||||
|
/* OS-level sockets. */ |
||||
|
|
||||
|
/* Event types generated by nn_usock. */ |
||||
|
#define NN_USOCK_CONNECTED 1 |
||||
|
#define NN_USOCK_ACCEPTED 2 |
||||
|
#define NN_USOCK_SENT 3 |
||||
|
#define NN_USOCK_RECEIVED 4 |
||||
|
#define NN_USOCK_ERROR 5 |
||||
|
#define NN_USOCK_ACCEPT_ERROR 6 |
||||
|
#define NN_USOCK_STOPPED 7 |
||||
|
#define NN_USOCK_SHUTDOWN 8 |
||||
|
|
||||
|
/* Maximum number of iovecs that can be passed to nn_usock_send function. */ |
||||
|
#define NN_USOCK_MAX_IOVCNT 3 |
||||
|
|
||||
|
/// Size of the buffer used for batch-reads of inbound data. To keep the performance optimal make sure that this value is larger than network MTU.
|
||||
|
//#define NN_USOCK_BATCH_SIZE 2048
|
||||
|
|
||||
|
#if defined NN_HAVE_WINDOWS |
||||
|
#include "usock_win.h" |
||||
|
#else |
||||
|
#include "usock_posix.h" |
||||
|
#endif |
||||
|
|
||||
|
void nn_usock_init (struct nn_usock *self, int src, struct nn_fsm *owner); |
||||
|
void nn_usock_term (struct nn_usock *self); |
||||
|
|
||||
|
int nn_usock_isidle (struct nn_usock *self); |
||||
|
int nn_usock_start (struct nn_usock *self, |
||||
|
int domain, int type, int protocol); |
||||
|
void nn_usock_start_fd (struct nn_usock *self, int fd); |
||||
|
void nn_usock_stop (struct nn_usock *self); |
||||
|
|
||||
|
void nn_usock_swap_owner (struct nn_usock *self, struct nn_fsm_owner *owner); |
||||
|
|
||||
|
int nn_usock_setsockopt (struct nn_usock *self, int level, int optname, |
||||
|
const void *optval, size_t optlen); |
||||
|
|
||||
|
int nn_usock_bind (struct nn_usock *self, const struct sockaddr *addr, |
||||
|
size_t addrlen); |
||||
|
int nn_usock_listen (struct nn_usock *self, int backlog); |
||||
|
|
||||
|
/* Accept a new connection from a listener. When done, NN_USOCK_ACCEPTED
|
||||
|
event will be delivered to the accepted socket. To cancel the operation, |
||||
|
stop the socket being accepted. Listening socket should not be stopped |
||||
|
while accepting a new socket is underway. */ |
||||
|
void nn_usock_accept (struct nn_usock *self, struct nn_usock *listener); |
||||
|
|
||||
|
/* When all the tuning is done on the accepted socket, call this function
|
||||
|
to activate standard data transfer phase. */ |
||||
|
void nn_usock_activate (struct nn_usock *self); |
||||
|
|
||||
|
/* Start connecting. Prior to this call the socket has to be bound to a local
|
||||
|
address. When connecting is done NN_USOCK_CONNECTED event will be reaised. |
||||
|
If connecting fails NN_USOCK_ERROR event will be raised. */ |
||||
|
void nn_usock_connect (struct nn_usock *self, const struct sockaddr *addr, |
||||
|
size_t addrlen); |
||||
|
|
||||
|
void nn_usock_send (struct nn_usock *self, const struct nn_iovec *iov, |
||||
|
int iovcnt); |
||||
|
void nn_usock_recv (struct nn_usock *self, void *buf, size_t len, int *fd); |
||||
|
|
||||
|
int nn_usock_geterrno (struct nn_usock *self); |
||||
|
|
||||
|
#endif |
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,77 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "fsm.h" |
||||
|
#include "worker.h" |
||||
|
|
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#ifndef __PNACL |
||||
|
#include <sys/uio.h> |
||||
|
#else |
||||
|
#include <glibc-compat/sys/uio.h> |
||||
|
#endif |
||||
|
|
||||
|
struct nn_usock { |
||||
|
|
||||
|
/* State machine base class. */ |
||||
|
struct nn_fsm fsm; |
||||
|
int32_t state,s; |
||||
|
struct nn_worker *worker; // The worker thread the usock is associated with
|
||||
|
struct nn_worker_fd wfd; // The underlying OS socket and handle that represents it in the poller
|
||||
|
struct // Members related to receiving data
|
||||
|
{ |
||||
|
// The buffer being filled in at the moment
|
||||
|
uint8_t *buf; |
||||
|
size_t len; |
||||
|
uint8_t *batch; // Buffer for batch-reading inbound data
|
||||
|
size_t batch_len; // Size of the batch buffer
|
||||
|
/* Current position in the batch buffer. The data preceding this
|
||||
|
position were already received by the user. The data that follow |
||||
|
will be received in the future. */ |
||||
|
size_t batch_pos; |
||||
|
/* File descriptor received via SCM_RIGHTS, if any. */ |
||||
|
int32_t *pfd; |
||||
|
} in; |
||||
|
struct // Members related to sending data
|
||||
|
{ |
||||
|
struct msghdr hdr; // msghdr being sent at the moment
|
||||
|
// List of buffers being sent at the moment. Referenced from 'hdr'
|
||||
|
struct iovec iov [NN_USOCK_MAX_IOVCNT]; |
||||
|
} out; |
||||
|
// Asynchronous tasks for the worker
|
||||
|
struct nn_worker_task task_connecting; |
||||
|
struct nn_worker_task task_connected; |
||||
|
struct nn_worker_task task_accept; |
||||
|
struct nn_worker_task task_send; |
||||
|
struct nn_worker_task task_recv; |
||||
|
struct nn_worker_task task_stop; |
||||
|
// Events raised by the usock
|
||||
|
struct nn_fsm_event event_established; |
||||
|
struct nn_fsm_event event_sent; |
||||
|
struct nn_fsm_event event_received; |
||||
|
struct nn_fsm_event event_error; |
||||
|
// In ACCEPTING state points to the socket being accepted. In BEING_ACCEPTED state points to the listener socket
|
||||
|
struct nn_usock *asock; |
||||
|
// Errno remembered in NN_USOCK_ERROR state
|
||||
|
int errnum; |
||||
|
}; |
File diff suppressed because it is too large
@ -0,0 +1,80 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "fsm.h" |
||||
|
#include "worker.h" |
||||
|
|
||||
|
#include "../utils/win.h" |
||||
|
|
||||
|
struct nn_usock { |
||||
|
|
||||
|
/* The state machine. */ |
||||
|
struct nn_fsm fsm; |
||||
|
int state; |
||||
|
|
||||
|
union { |
||||
|
|
||||
|
/* The actual underlying socket. Can be used as a HANDLE too. */ |
||||
|
SOCKET s; |
||||
|
|
||||
|
/* Named pipe handle. Cannot be used as a SOCKET. */ |
||||
|
HANDLE p; |
||||
|
}; |
||||
|
|
||||
|
/* For NamedPipes, closing an accepted pipe differs from other pipes.
|
||||
|
If the NamedPipe was accepted, this member is set to 1. 0 otherwise. */ |
||||
|
int isaccepted; |
||||
|
|
||||
|
/* Asynchronous operations being executed on the socket. */ |
||||
|
struct nn_worker_op in; |
||||
|
struct nn_worker_op out; |
||||
|
|
||||
|
/* When accepting new socket, they have to be created with same
|
||||
|
type as the listening socket. Thus, in listening socket we |
||||
|
have to store its exact type. */ |
||||
|
int domain; |
||||
|
int type; |
||||
|
int protocol; |
||||
|
|
||||
|
/* Events raised by the usock. */ |
||||
|
struct nn_fsm_event event_established; |
||||
|
struct nn_fsm_event event_sent; |
||||
|
struct nn_fsm_event event_received; |
||||
|
struct nn_fsm_event event_error; |
||||
|
|
||||
|
/* In ACCEPTING state points to the socket being accepted.
|
||||
|
In BEING_ACCEPTED state points to the listener socket. */ |
||||
|
struct nn_usock *asock; |
||||
|
|
||||
|
/* Buffer allocated for output of AcceptEx function. If accepting is not
|
||||
|
done on this socket, the field is set to NULL. */ |
||||
|
void *ainfo; |
||||
|
|
||||
|
/* For NamedPipes, we store the address inside the socket. */ |
||||
|
struct sockaddr_un pipename; |
||||
|
|
||||
|
/* For now we allocate a new buffer for each write to a named pipe. */ |
||||
|
void *pipesendbuf; |
||||
|
|
||||
|
/* Errno remembered in NN_USOCK_ERROR state */ |
||||
|
int errnum; |
||||
|
}; |
@ -0,0 +1,45 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "worker.h" |
||||
|
|
||||
|
#if defined NN_HAVE_WINDOWS |
||||
|
#include "worker_win.c" |
||||
|
#else |
||||
|
#include "worker_posix.c" |
||||
|
#endif |
||||
|
|
||||
|
void nn_worker_timer_init (struct nn_worker_timer *self, struct nn_fsm *owner) |
||||
|
{ |
||||
|
self->owner = owner; |
||||
|
nn_timerset_hndl_init (&self->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_timer_term (struct nn_worker_timer *self) |
||||
|
{ |
||||
|
nn_timerset_hndl_term (&self->hndl); |
||||
|
} |
||||
|
|
||||
|
int nn_worker_timer_isactive (struct nn_worker_timer *self) |
||||
|
{ |
||||
|
return nn_timerset_hndl_isactive (&self->hndl); |
||||
|
} |
@ -0,0 +1,69 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_WORKER_INCLUDED |
||||
|
#define NN_WORKER_INCLUDED |
||||
|
|
||||
|
#include "fsm.h" |
||||
|
#include "timerset.h" |
||||
|
|
||||
|
#if defined NN_HAVE_WINDOWS |
||||
|
#include "worker_win.h" |
||||
|
#else |
||||
|
#include "worker_posix.h" |
||||
|
#endif |
||||
|
|
||||
|
#define NN_WORKER_TIMER_TIMEOUT 1 |
||||
|
|
||||
|
struct nn_worker_timer { |
||||
|
struct nn_fsm *owner; |
||||
|
struct nn_timerset_hndl hndl; |
||||
|
}; |
||||
|
|
||||
|
void nn_worker_timer_init (struct nn_worker_timer *self, |
||||
|
struct nn_fsm *owner); |
||||
|
void nn_worker_timer_term (struct nn_worker_timer *self); |
||||
|
int nn_worker_timer_isactive (struct nn_worker_timer *self); |
||||
|
|
||||
|
#define NN_WORKER_TASK_EXECUTE 1 |
||||
|
|
||||
|
struct nn_worker_task; |
||||
|
|
||||
|
void nn_worker_task_init (struct nn_worker_task *self, int src, |
||||
|
struct nn_fsm *owner); |
||||
|
void nn_worker_task_term (struct nn_worker_task *self); |
||||
|
|
||||
|
struct nn_worker; |
||||
|
|
||||
|
int nn_worker_init (struct nn_worker *self); |
||||
|
void nn_worker_term (struct nn_worker *self); |
||||
|
void nn_worker_execute (struct nn_worker *self, struct nn_worker_task *task); |
||||
|
void nn_worker_cancel (struct nn_worker *self, struct nn_worker_task *task); |
||||
|
|
||||
|
void nn_worker_add_timer (struct nn_worker *self, int timeout, |
||||
|
struct nn_worker_timer *timer); |
||||
|
void nn_worker_rm_timer (struct nn_worker *self, |
||||
|
struct nn_worker_timer *timer); |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,242 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013-2014 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "ctx.h" |
||||
|
|
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/fast.h" |
||||
|
#include "../utils/cont.h" |
||||
|
#include "../utils/attr.h" |
||||
|
#include "../utils/queue.h" |
||||
|
|
||||
|
/* Private functions. */ |
||||
|
static void nn_worker_routine (void *arg); |
||||
|
|
||||
|
void nn_worker_fd_init (struct nn_worker_fd *self, int src, |
||||
|
struct nn_fsm *owner) |
||||
|
{ |
||||
|
self->src = src; |
||||
|
self->owner = owner; |
||||
|
} |
||||
|
|
||||
|
void nn_worker_fd_term (NN_UNUSED struct nn_worker_fd *self) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
void nn_worker_add_fd (struct nn_worker *self, int s, struct nn_worker_fd *fd) |
||||
|
{ |
||||
|
nn_poller_add (&((struct nn_worker*) self)->poller, s, &fd->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_rm_fd (struct nn_worker *self, struct nn_worker_fd *fd) |
||||
|
{ |
||||
|
nn_poller_rm (&((struct nn_worker*) self)->poller, &fd->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_set_in (struct nn_worker *self, struct nn_worker_fd *fd) |
||||
|
{ |
||||
|
nn_poller_set_in (&((struct nn_worker*) self)->poller, &fd->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_reset_in (struct nn_worker *self, struct nn_worker_fd *fd) |
||||
|
{ |
||||
|
nn_poller_reset_in (&((struct nn_worker*) self)->poller, &fd->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_set_out (struct nn_worker *self, struct nn_worker_fd *fd) |
||||
|
{ |
||||
|
nn_poller_set_out (&((struct nn_worker*) self)->poller, &fd->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_reset_out (struct nn_worker *self, struct nn_worker_fd *fd) |
||||
|
{ |
||||
|
nn_poller_reset_out (&((struct nn_worker*) self)->poller, &fd->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_add_timer (struct nn_worker *self, int timeout, |
||||
|
struct nn_worker_timer *timer) |
||||
|
{ |
||||
|
nn_timerset_add (&((struct nn_worker*) self)->timerset, timeout, |
||||
|
&timer->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_rm_timer (struct nn_worker *self, struct nn_worker_timer *timer) |
||||
|
{ |
||||
|
nn_timerset_rm (&((struct nn_worker*) self)->timerset, &timer->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_task_init (struct nn_worker_task *self, int src, |
||||
|
struct nn_fsm *owner) |
||||
|
{ |
||||
|
self->src = src; |
||||
|
self->owner = owner; |
||||
|
nn_queue_item_init(&self->item); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_task_term (struct nn_worker_task *self) |
||||
|
{ |
||||
|
nn_queue_item_term (&self->item); |
||||
|
} |
||||
|
|
||||
|
int nn_worker_init(struct nn_worker *self) |
||||
|
{ |
||||
|
int32_t rc; |
||||
|
//PostMessage("nn_worker_init %p\n",self);
|
||||
|
rc = nn_efd_init(&self->efd); |
||||
|
//PostMessage("efd init: rc.%d\n",rc);
|
||||
|
if ( rc < 0 ) |
||||
|
return rc; |
||||
|
//PostMessage("nn_mutex_init\n");
|
||||
|
nn_mutex_init(&self->sync); |
||||
|
//PostMessage("nn_queue_init\n");
|
||||
|
nn_queue_init(&self->tasks); |
||||
|
//PostMessage("nn_queue_item_init\n");
|
||||
|
nn_queue_item_init(&self->stop); |
||||
|
//PostMessage("nn_poller_init\n");
|
||||
|
nn_poller_init(&self->poller); |
||||
|
//PostMessage("nn_poller_add\n");
|
||||
|
nn_poller_add(&self->poller,nn_efd_getfd(&self->efd),&self->efd_hndl); |
||||
|
//PostMessage("nn_poller_set_in\n");
|
||||
|
nn_poller_set_in(&self->poller, &self->efd_hndl); |
||||
|
//PostMessage("nn_timerset_init\n");
|
||||
|
nn_timerset_init(&self->timerset); |
||||
|
//PostMessage("nn_thread_init\n");
|
||||
|
nn_thread_init(&self->thread,nn_worker_routine, self); |
||||
|
//PostMessage("finished nn_worker_init\n");
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void nn_worker_term (struct nn_worker *self) |
||||
|
{ |
||||
|
/* Ask worker thread to terminate. */ |
||||
|
nn_mutex_lock (&self->sync); |
||||
|
nn_queue_push (&self->tasks, &self->stop); |
||||
|
nn_efd_signal (&self->efd); |
||||
|
nn_mutex_unlock (&self->sync); |
||||
|
|
||||
|
/* Wait till worker thread terminates. */ |
||||
|
nn_thread_term (&self->thread); |
||||
|
|
||||
|
/* Clean up. */ |
||||
|
nn_timerset_term (&self->timerset); |
||||
|
nn_poller_term (&self->poller); |
||||
|
nn_efd_term (&self->efd); |
||||
|
nn_queue_item_term (&self->stop); |
||||
|
nn_queue_term (&self->tasks); |
||||
|
nn_mutex_term (&self->sync); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_execute (struct nn_worker *self, struct nn_worker_task *task) |
||||
|
{ |
||||
|
nn_mutex_lock (&self->sync); |
||||
|
nn_queue_push (&self->tasks, &task->item); |
||||
|
nn_efd_signal (&self->efd); |
||||
|
nn_mutex_unlock (&self->sync); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_cancel (struct nn_worker *self, struct nn_worker_task *task) |
||||
|
{ |
||||
|
nn_mutex_lock (&self->sync); |
||||
|
nn_queue_remove (&self->tasks, &task->item); |
||||
|
nn_mutex_unlock (&self->sync); |
||||
|
} |
||||
|
|
||||
|
static void nn_worker_routine (void *arg) |
||||
|
{ |
||||
|
int32_t rc,pevent; |
||||
|
struct nn_worker *self; |
||||
|
struct nn_poller_hndl *phndl; |
||||
|
struct nn_timerset_hndl *thndl; |
||||
|
struct nn_queue tasks; |
||||
|
struct nn_queue_item *item; |
||||
|
struct nn_worker_task *task; |
||||
|
struct nn_worker_fd *fd; |
||||
|
struct nn_worker_timer *timer; |
||||
|
//PostMessage("nn_worker_routine started\n");
|
||||
|
self = (struct nn_worker*) arg; |
||||
|
while ( 1 ) // Infinite loop. It will be interrupted only when the object is shut down.
|
||||
|
{ |
||||
|
// Wait for new events and/or timeouts.
|
||||
|
rc = nn_poller_wait(&self->poller,nn_timerset_timeout (&self->timerset)); |
||||
|
errnum_assert(rc == 0, -rc); |
||||
|
while ( 1 ) // Process all expired timers
|
||||
|
{ |
||||
|
rc = nn_timerset_event(&self->timerset, &thndl); |
||||
|
if ( rc == -EAGAIN ) |
||||
|
break; |
||||
|
//PostMessage("nn_worker process expired user\n");
|
||||
|
errnum_assert(rc == 0, -rc); |
||||
|
timer = nn_cont(thndl, struct nn_worker_timer, hndl); |
||||
|
nn_ctx_enter(timer->owner->ctx); |
||||
|
nn_fsm_feed(timer->owner,-1,NN_WORKER_TIMER_TIMEOUT,timer); |
||||
|
nn_ctx_leave(timer->owner->ctx); |
||||
|
} |
||||
|
while ( 1 ) // Process all events from the poller
|
||||
|
{ |
||||
|
rc = nn_poller_event(&self->poller,&pevent,&phndl); // Get next poller event, such as IN or OUT
|
||||
|
if ( nn_slow(rc == -EAGAIN) ) |
||||
|
break; |
||||
|
//PostMessage("nn_worker process all events from the poller\n");
|
||||
|
if ( phndl == &self->efd_hndl ) // If there are any new incoming worker tasks, process them
|
||||
|
{ |
||||
|
nn_assert (pevent == NN_POLLER_IN); |
||||
|
// Make a local copy of the task queue. This way the application threads are not blocked and can post new tasks while the existing tasks are being processed. Also, new tasks can be posted from within task handlers
|
||||
|
nn_mutex_lock(&self->sync); |
||||
|
nn_efd_unsignal(&self->efd); |
||||
|
memcpy(&tasks,&self->tasks,sizeof(tasks)); |
||||
|
nn_queue_init(&self->tasks); |
||||
|
nn_mutex_unlock(&self->sync); |
||||
|
while ( 1 ) |
||||
|
{ |
||||
|
item = nn_queue_pop(&tasks); // Next worker task
|
||||
|
if ( nn_slow(!item) ) |
||||
|
break; |
||||
|
//PostMessage("nn_worker next worker task\n");
|
||||
|
if ( nn_slow(item == &self->stop) ) // If the worker thread is asked to stop, do so
|
||||
|
{ |
||||
|
nn_queue_term(&tasks); |
||||
|
return; |
||||
|
} |
||||
|
// It's a user-defined task. Notify the user that it has arrived in the worker thread
|
||||
|
//PostMessage("nn_worker user defined task\n");
|
||||
|
task = nn_cont(item,struct nn_worker_task,item); |
||||
|
nn_ctx_enter(task->owner->ctx); |
||||
|
nn_fsm_feed(task->owner,task->src,NN_WORKER_TASK_EXECUTE,task); |
||||
|
nn_ctx_leave (task->owner->ctx); |
||||
|
} |
||||
|
nn_queue_term (&tasks); |
||||
|
continue; |
||||
|
} |
||||
|
//PostMessage("nn_worker true i/o, invoke handler\n");
|
||||
|
fd = nn_cont(phndl,struct nn_worker_fd,hndl); // It's a true I/O event. Invoke the handler
|
||||
|
//PostMessage("nn_worker true i/o, fd.%p\n",fd);
|
||||
|
nn_ctx_enter(fd->owner->ctx); |
||||
|
//PostMessage("nn_worker true i/o, after nn_ctx_enter\n");
|
||||
|
nn_fsm_feed(fd->owner,fd->src,pevent,fd); |
||||
|
//PostMessage("nn_worker true i/o, after nn_fsm_feed leave.%p\n",fd->owner->ctx);
|
||||
|
nn_ctx_leave(fd->owner->ctx); |
||||
|
//PostMessage("nn_worker true i/o, after nn_ctx_leave\n");
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,67 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../utils/queue.h" |
||||
|
#include "../utils/mutex.h" |
||||
|
#include "../utils/thread.h" |
||||
|
#include "../utils/efd.h" |
||||
|
|
||||
|
#include "poller.h" |
||||
|
|
||||
|
#define NN_WORKER_FD_IN NN_POLLER_IN |
||||
|
#define NN_WORKER_FD_OUT NN_POLLER_OUT |
||||
|
#define NN_WORKER_FD_ERR NN_POLLER_ERR |
||||
|
|
||||
|
struct nn_worker_fd { |
||||
|
int src; |
||||
|
struct nn_fsm *owner; |
||||
|
struct nn_poller_hndl hndl; |
||||
|
}; |
||||
|
|
||||
|
void nn_worker_fd_init (struct nn_worker_fd *self, int src, |
||||
|
struct nn_fsm *owner); |
||||
|
void nn_worker_fd_term (struct nn_worker_fd *self); |
||||
|
|
||||
|
struct nn_worker_task { |
||||
|
int src; |
||||
|
struct nn_fsm *owner; |
||||
|
struct nn_queue_item item; |
||||
|
}; |
||||
|
|
||||
|
struct nn_worker { |
||||
|
struct nn_mutex sync; |
||||
|
struct nn_queue tasks; |
||||
|
struct nn_queue_item stop; |
||||
|
struct nn_efd efd; |
||||
|
struct nn_poller poller; |
||||
|
struct nn_poller_hndl efd_hndl; |
||||
|
struct nn_timerset timerset; |
||||
|
struct nn_thread thread; |
||||
|
}; |
||||
|
|
||||
|
void nn_worker_add_fd (struct nn_worker *self, int s, struct nn_worker_fd *fd); |
||||
|
void nn_worker_rm_fd(struct nn_worker *self, struct nn_worker_fd *fd); |
||||
|
void nn_worker_set_in (struct nn_worker *self, struct nn_worker_fd *fd); |
||||
|
void nn_worker_reset_in (struct nn_worker *self, struct nn_worker_fd *fd); |
||||
|
void nn_worker_set_out (struct nn_worker *self, struct nn_worker_fd *fd); |
||||
|
void nn_worker_reset_out (struct nn_worker *self, struct nn_worker_fd *fd); |
@ -0,0 +1,222 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "ctx.h" |
||||
|
#include "usock.h" |
||||
|
|
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/cont.h" |
||||
|
#include "../utils/fast.h" |
||||
|
|
||||
|
#define NN_WORKER_MAX_EVENTS 32 |
||||
|
|
||||
|
#define NN_WORKER_OP_STATE_IDLE 1 |
||||
|
#define NN_WORKER_OP_STATE_ACTIVE 2 |
||||
|
#define NN_WORKER_OP_STATE_ACTIVE_ZEROISERROR 3 |
||||
|
|
||||
|
/* The value of this variable is irrelevant. It's used only as a placeholder
|
||||
|
for the address that is used as the 'stop' event ID. */ |
||||
|
const int nn_worker_stop = 0; |
||||
|
|
||||
|
/* Private functions. */ |
||||
|
static void nn_worker_routine (void *arg); |
||||
|
|
||||
|
void nn_worker_task_init (struct nn_worker_task *self, int src, |
||||
|
struct nn_fsm *owner) |
||||
|
{ |
||||
|
self->src = src; |
||||
|
self->owner = owner; |
||||
|
} |
||||
|
|
||||
|
void nn_worker_task_term (struct nn_worker_task *self) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
void nn_worker_op_init (struct nn_worker_op *self, int src, |
||||
|
struct nn_fsm *owner) |
||||
|
{ |
||||
|
self->src = src; |
||||
|
self->owner = owner; |
||||
|
self->state = NN_WORKER_OP_STATE_IDLE; |
||||
|
} |
||||
|
|
||||
|
void nn_worker_op_term (struct nn_worker_op *self) |
||||
|
{ |
||||
|
nn_assert_state (self, NN_WORKER_OP_STATE_IDLE); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_op_start (struct nn_worker_op *self, int zeroiserror) |
||||
|
{ |
||||
|
nn_assert_state (self, NN_WORKER_OP_STATE_IDLE); |
||||
|
self->state = zeroiserror ? NN_WORKER_OP_STATE_ACTIVE_ZEROISERROR : |
||||
|
NN_WORKER_OP_STATE_ACTIVE; |
||||
|
} |
||||
|
|
||||
|
int nn_worker_op_isidle (struct nn_worker_op *self) |
||||
|
{ |
||||
|
return self->state == NN_WORKER_OP_STATE_IDLE ? 1 : 0; |
||||
|
} |
||||
|
|
||||
|
int nn_worker_init (struct nn_worker *self) |
||||
|
{ |
||||
|
self->cp = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 0); |
||||
|
win_assert (self->cp); |
||||
|
nn_timerset_init (&self->timerset); |
||||
|
nn_thread_init (&self->thread, nn_worker_routine, self); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void nn_worker_term (struct nn_worker *self) |
||||
|
{ |
||||
|
BOOL brc; |
||||
|
|
||||
|
/* Ask worker thread to terminate. */ |
||||
|
brc = PostQueuedCompletionStatus (self->cp, 0, |
||||
|
(ULONG_PTR) &nn_worker_stop, NULL); |
||||
|
win_assert (brc); |
||||
|
|
||||
|
/* Wait till worker thread terminates. */ |
||||
|
nn_thread_term (&self->thread); |
||||
|
|
||||
|
nn_timerset_term (&self->timerset); |
||||
|
brc = CloseHandle (self->cp); |
||||
|
win_assert (brc); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_execute (struct nn_worker *self, struct nn_worker_task *task) |
||||
|
{ |
||||
|
BOOL brc; |
||||
|
|
||||
|
brc = PostQueuedCompletionStatus (self->cp, 0, (ULONG_PTR) task, NULL); |
||||
|
win_assert (brc); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_add_timer (struct nn_worker *self, int timeout, |
||||
|
struct nn_worker_timer *timer) |
||||
|
{ |
||||
|
nn_timerset_add (&((struct nn_worker*) self)->timerset, timeout, |
||||
|
&timer->hndl); |
||||
|
} |
||||
|
|
||||
|
void nn_worker_rm_timer (struct nn_worker *self, struct nn_worker_timer *timer) |
||||
|
{ |
||||
|
nn_timerset_rm (&((struct nn_worker*) self)->timerset, &timer->hndl); |
||||
|
} |
||||
|
|
||||
|
HANDLE nn_worker_getcp (struct nn_worker *self) |
||||
|
{ |
||||
|
return self->cp; |
||||
|
} |
||||
|
|
||||
|
static void nn_worker_routine (void *arg) |
||||
|
{ |
||||
|
int rc; |
||||
|
BOOL brc; |
||||
|
struct nn_worker *self; |
||||
|
int timeout; |
||||
|
ULONG count; |
||||
|
ULONG i; |
||||
|
struct nn_timerset_hndl *thndl; |
||||
|
struct nn_worker_timer *timer; |
||||
|
struct nn_worker_task *task; |
||||
|
struct nn_worker_op *op; |
||||
|
OVERLAPPED_ENTRY entries [NN_WORKER_MAX_EVENTS]; |
||||
|
|
||||
|
self = (struct nn_worker*) arg; |
||||
|
|
||||
|
while (1) { |
||||
|
|
||||
|
/* Process all expired timers. */ |
||||
|
while (1) { |
||||
|
rc = nn_timerset_event (&self->timerset, &thndl); |
||||
|
if (nn_fast (rc == -EAGAIN)) |
||||
|
break; |
||||
|
errnum_assert (rc == 0, -rc); |
||||
|
timer = nn_cont (thndl, struct nn_worker_timer, hndl); |
||||
|
nn_ctx_enter (timer->owner->ctx); |
||||
|
nn_fsm_feed (timer->owner, -1, NN_WORKER_TIMER_TIMEOUT, timer); |
||||
|
nn_ctx_leave (timer->owner->ctx); |
||||
|
} |
||||
|
|
||||
|
/* Compute the time interval till next timer expiration. */ |
||||
|
timeout = nn_timerset_timeout (&self->timerset); |
||||
|
|
||||
|
/* Wait for new events and/or timeouts. */ |
||||
|
brc = GetQueuedCompletionStatusEx (self->cp, entries, |
||||
|
NN_WORKER_MAX_EVENTS, &count, timeout < 0 ? INFINITE : timeout, |
||||
|
FALSE); |
||||
|
if (nn_slow (!brc && GetLastError () == WAIT_TIMEOUT)) |
||||
|
continue; |
||||
|
win_assert (brc); |
||||
|
|
||||
|
for (i = 0; i != count; ++i) { |
||||
|
|
||||
|
/* Process I/O completion events. */ |
||||
|
if (nn_fast (entries [i].lpOverlapped)) { |
||||
|
op = nn_cont (entries [i].lpOverlapped, |
||||
|
struct nn_worker_op, olpd); |
||||
|
|
||||
|
/* The 'Internal' field is actually an NTSTATUS. Report
|
||||
|
success and error. Ignore warnings and informational |
||||
|
messages.*/ |
||||
|
rc = entries [i].Internal & 0xc0000000; |
||||
|
switch (rc) { |
||||
|
case 0x00000000: |
||||
|
rc = NN_WORKER_OP_DONE; |
||||
|
break; |
||||
|
case 0xc0000000: |
||||
|
rc = NN_WORKER_OP_ERROR; |
||||
|
break; |
||||
|
default: |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
/* Raise the completion event. */ |
||||
|
nn_ctx_enter (op->owner->ctx); |
||||
|
nn_assert (op->state != NN_WORKER_OP_STATE_IDLE); |
||||
|
if (rc != NN_WORKER_OP_ERROR && |
||||
|
op->state == NN_WORKER_OP_STATE_ACTIVE_ZEROISERROR && |
||||
|
entries [i].dwNumberOfBytesTransferred == 0) |
||||
|
rc = NN_WORKER_OP_ERROR; |
||||
|
op->state = NN_WORKER_OP_STATE_IDLE; |
||||
|
nn_fsm_feed (op->owner, op->src, rc, op); |
||||
|
nn_ctx_leave (op->owner->ctx); |
||||
|
|
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
/* Worker thread shutdown is requested. */ |
||||
|
if (nn_slow (entries [i].lpCompletionKey == |
||||
|
(ULONG_PTR) &nn_worker_stop)) |
||||
|
return; |
||||
|
|
||||
|
/* Process tasks. */ |
||||
|
task = (struct nn_worker_task*) entries [i].lpCompletionKey; |
||||
|
nn_ctx_enter (task->owner->ctx); |
||||
|
nn_fsm_feed (task->owner, task->src, |
||||
|
NN_WORKER_TASK_EXECUTE, task); |
||||
|
nn_ctx_leave (task->owner->ctx); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,64 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "fsm.h" |
||||
|
#include "timerset.h" |
||||
|
|
||||
|
#include "../utils/win.h" |
||||
|
#include "../utils/thread.h" |
||||
|
|
||||
|
struct nn_worker_task { |
||||
|
int src; |
||||
|
struct nn_fsm *owner; |
||||
|
}; |
||||
|
|
||||
|
#define NN_WORKER_OP_DONE 1 |
||||
|
#define NN_WORKER_OP_ERROR 2 |
||||
|
|
||||
|
struct nn_worker_op { |
||||
|
int src; |
||||
|
struct nn_fsm *owner; |
||||
|
int state; |
||||
|
|
||||
|
/* This structure is to be used by the user, not nn_worker_op itself.
|
||||
|
Actual usage is specific to the asynchronous operation in question. */ |
||||
|
OVERLAPPED olpd; |
||||
|
}; |
||||
|
|
||||
|
void nn_worker_op_init (struct nn_worker_op *self, int src, |
||||
|
struct nn_fsm *owner); |
||||
|
void nn_worker_op_term (struct nn_worker_op *self); |
||||
|
|
||||
|
/* Call this function when asynchronous operation is started.
|
||||
|
If 'zeroiserror' is set to 1, zero bytes transferred will be treated |
||||
|
as an error. */ |
||||
|
void nn_worker_op_start (struct nn_worker_op *self, int zeroiserror); |
||||
|
|
||||
|
int nn_worker_op_isidle (struct nn_worker_op *self); |
||||
|
|
||||
|
struct nn_worker { |
||||
|
HANDLE cp; |
||||
|
struct nn_timerset timerset; |
||||
|
struct nn_thread thread; |
||||
|
}; |
||||
|
|
||||
|
HANDLE nn_worker_getcp (struct nn_worker *self); |
@ -0,0 +1,39 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef BUS_H_INCLUDED |
||||
|
#define BUS_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_PROTO_BUS 7 |
||||
|
|
||||
|
#define NN_BUS (NN_PROTO_BUS * 16 + 0) |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,3 @@ |
|||||
|
In this directory all the generic code of the library resides. I.e. the code |
||||
|
that is not a transport, not a protocol, not a generic utility, rather a glue |
||||
|
between the pieces. |
@ -0,0 +1,190 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../transport.h" |
||||
|
|
||||
|
#include "ep.h" |
||||
|
#include "sock.h" |
||||
|
|
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/cont.h" |
||||
|
#include "../utils/fast.h" |
||||
|
#include "../utils/attr.h" |
||||
|
|
||||
|
#include <string.h> |
||||
|
|
||||
|
#define NN_EP_STATE_IDLE 1 |
||||
|
#define NN_EP_STATE_ACTIVE 2 |
||||
|
#define NN_EP_STATE_STOPPING 3 |
||||
|
|
||||
|
#define NN_EP_ACTION_STOPPED 1 |
||||
|
|
||||
|
/* Private functions. */ |
||||
|
static void nn_ep_handler (struct nn_fsm *self,int32_t src,int32_t type,void *srcptr); |
||||
|
static void nn_ep_shutdown (struct nn_fsm *self,int32_t src,int32_t type,void *srcptr); |
||||
|
|
||||
|
int32_t nn_ep_init(struct nn_ep *self,int32_t src,struct nn_sock *sock,int32_t eid,struct nn_transport *transport,int32_t bind,const char *addr) |
||||
|
{ |
||||
|
int32_t rc; |
||||
|
nn_fsm_init(&self->fsm,nn_ep_handler,nn_ep_shutdown,src,self,&sock->fsm); |
||||
|
self->state = NN_EP_STATE_IDLE; |
||||
|
self->epbase = NULL; |
||||
|
self->sock = sock; |
||||
|
self->eid = eid; |
||||
|
self->last_errno = 0; |
||||
|
//PostMessage("ep_init.(%s) eid.%d <- %s://%s bind.%d\n",sock->socket_name,eid,transport->name,addr,bind);
|
||||
|
nn_list_item_init(&self->item); |
||||
|
memcpy(&self->options,&sock->ep_template,sizeof(struct nn_ep_options)); |
||||
|
nn_assert(strlen (addr) <= NN_SOCKADDR_MAX); // Store the textual form of the address.
|
||||
|
strcpy(self->addr,addr); |
||||
|
// Create transport-specific part of the endpoint
|
||||
|
if ( bind != 0 ) |
||||
|
rc = transport->bind((void *)self,&self->epbase); |
||||
|
else rc = transport->connect((void *)self,&self->epbase); |
||||
|
self->bind = bind, self->transport = transport; |
||||
|
if ( rc < 0 ) // Endpoint creation failed
|
||||
|
{ |
||||
|
nn_list_item_term(&self->item); |
||||
|
nn_fsm_term(&self->fsm); |
||||
|
return rc; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void nn_ep_term(struct nn_ep *self) |
||||
|
{ |
||||
|
nn_assert_state(self,NN_EP_STATE_IDLE); |
||||
|
self->epbase->vfptr->destroy(self->epbase); |
||||
|
nn_list_item_term(&self->item); |
||||
|
nn_fsm_term(&self->fsm); |
||||
|
} |
||||
|
|
||||
|
void nn_ep_start(struct nn_ep *self) { nn_fsm_start(&self->fsm); } |
||||
|
|
||||
|
void nn_ep_stop(struct nn_ep *self) { nn_fsm_stop(&self->fsm); } |
||||
|
|
||||
|
void nn_ep_stopped(struct nn_ep *self) |
||||
|
{ |
||||
|
// TODO: Do the following in a more sane way
|
||||
|
self->fsm.stopped.fsm = &self->fsm; |
||||
|
self->fsm.stopped.src = NN_FSM_ACTION; |
||||
|
self->fsm.stopped.srcptr = NULL; |
||||
|
self->fsm.stopped.type = NN_EP_ACTION_STOPPED; |
||||
|
nn_ctx_raise(self->fsm.ctx,&self->fsm.stopped); |
||||
|
} |
||||
|
|
||||
|
struct nn_ctx *nn_ep_getctx (struct nn_ep *self) { return nn_sock_getctx (self->sock); } |
||||
|
|
||||
|
const char *nn_ep_getaddr(struct nn_ep *self) { return self->addr; } |
||||
|
|
||||
|
void nn_ep_getopt(struct nn_ep *self,int32_t level,int32_t option,void *optval,size_t *optvallen) |
||||
|
{ |
||||
|
int32_t rc; |
||||
|
rc = nn_sock_getopt_inner(self->sock,level,option,optval,optvallen); |
||||
|
errnum_assert (rc == 0, -rc); |
||||
|
} |
||||
|
|
||||
|
int nn_ep_ispeer(struct nn_ep *self,int32_t socktype) { return nn_sock_ispeer(self->sock, socktype); } |
||||
|
|
||||
|
static void nn_ep_shutdown(struct nn_fsm *self,int32_t src,int32_t type,NN_UNUSED void *srcptr) |
||||
|
{ |
||||
|
struct nn_ep *ep; |
||||
|
ep = nn_cont(self,struct nn_ep,fsm); |
||||
|
if ( nn_slow(src == NN_FSM_ACTION && type == NN_FSM_STOP) ) |
||||
|
{ |
||||
|
ep->epbase->vfptr->stop(ep->epbase); |
||||
|
ep->state = NN_EP_STATE_STOPPING; |
||||
|
return; |
||||
|
} |
||||
|
if ( nn_slow(ep->state == NN_EP_STATE_STOPPING) ) |
||||
|
{ |
||||
|
if ( src != NN_FSM_ACTION || type != NN_EP_ACTION_STOPPED ) |
||||
|
return; |
||||
|
ep->state = NN_EP_STATE_IDLE; |
||||
|
nn_fsm_stopped(&ep->fsm,NN_EP_STOPPED); |
||||
|
return; |
||||
|
} |
||||
|
nn_fsm_bad_state(ep->state,src,type); |
||||
|
} |
||||
|
|
||||
|
static void nn_ep_handler (struct nn_fsm *self,int32_t src,int32_t type,NN_UNUSED void *srcptr) |
||||
|
{ |
||||
|
struct nn_ep *ep; |
||||
|
ep = nn_cont(self,struct nn_ep,fsm); |
||||
|
switch ( ep->state ) |
||||
|
{ |
||||
|
/******************************************************************************/ |
||||
|
/* IDLE state. */ |
||||
|
/******************************************************************************/ |
||||
|
case NN_EP_STATE_IDLE: |
||||
|
switch ( src ) |
||||
|
{ |
||||
|
|
||||
|
case NN_FSM_ACTION: |
||||
|
switch ( type ) |
||||
|
{ |
||||
|
case NN_FSM_START: |
||||
|
ep->state = NN_EP_STATE_ACTIVE; |
||||
|
return; |
||||
|
default: |
||||
|
nn_fsm_bad_action(ep->state,src,type); |
||||
|
} |
||||
|
default: |
||||
|
nn_fsm_bad_source(ep->state,src,type); |
||||
|
} |
||||
|
/******************************************************************************/ |
||||
|
/* ACTIVE state. */ |
||||
|
/* We don't expect any events in this state. The only thing that can be done */ |
||||
|
/* is closing the endpoint. */ |
||||
|
/******************************************************************************/ |
||||
|
case NN_EP_STATE_ACTIVE: |
||||
|
nn_fsm_bad_source(ep->state, src, type); |
||||
|
/******************************************************************************/ |
||||
|
/* Invalid state. */ |
||||
|
/******************************************************************************/ |
||||
|
default: |
||||
|
nn_fsm_bad_state(ep->state, src, type); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void nn_ep_stat_increment(struct nn_ep *self, int name, int increment) { nn_sock_stat_increment (self->sock, name, increment); } |
||||
|
|
||||
|
void nn_ep_set_error(struct nn_ep *self,int32_t errnum,char *fname,int32_t linenum) |
||||
|
{ |
||||
|
if ( self->last_errno == errnum ) // Error is still there, no need to report it again
|
||||
|
return; |
||||
|
if ( self->last_errno == 0 ) |
||||
|
nn_sock_stat_increment(self->sock,NN_STAT_CURRENT_EP_ERRORS,1); |
||||
|
self->last_errno = errnum; |
||||
|
nn_sock_report_error(self->sock,self,errnum,fname,linenum); |
||||
|
} |
||||
|
|
||||
|
void nn_ep_clear_error(struct nn_ep *self) |
||||
|
{ |
||||
|
if ( self->last_errno == 0 ) // Error is already clear, no need to report it
|
||||
|
return; |
||||
|
nn_sock_stat_increment(self->sock,NN_STAT_CURRENT_EP_ERRORS,-1); |
||||
|
self->last_errno = 0; |
||||
|
nn_sock_report_error(self->sock,self,0,"clear error",0); |
||||
|
} |
||||
|
|
@ -0,0 +1,64 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_EP_INCLUDED |
||||
|
#define NN_EP_INCLUDED |
||||
|
|
||||
|
#include "../transport.h" |
||||
|
|
||||
|
#include "../aio/fsm.h" |
||||
|
|
||||
|
#include "../utils/list.h" |
||||
|
|
||||
|
/* Events generated by the nn_ep object. */ |
||||
|
#define NN_EP_STOPPED 1 |
||||
|
|
||||
|
struct nn_ep |
||||
|
{ |
||||
|
struct nn_fsm fsm; |
||||
|
int32_t state,bind,eid,last_errno; |
||||
|
struct nn_transport *transport; |
||||
|
struct nn_epbase *epbase; |
||||
|
struct nn_sock *sock; |
||||
|
struct nn_ep_options options; |
||||
|
struct nn_list_item item; |
||||
|
char addr[NN_SOCKADDR_MAX + 1]; |
||||
|
}; |
||||
|
|
||||
|
int nn_ep_init(struct nn_ep *self, int src, struct nn_sock *sock, int eid,struct nn_transport *transport, int bind, const char *addr); |
||||
|
void nn_ep_term(struct nn_ep *self); |
||||
|
|
||||
|
void nn_ep_start(struct nn_ep *self); |
||||
|
void nn_ep_stop(struct nn_ep *self); |
||||
|
|
||||
|
void nn_ep_stopped(struct nn_ep *self); |
||||
|
|
||||
|
struct nn_ctx *nn_ep_getctx(struct nn_ep *self); |
||||
|
const char *nn_ep_getaddr(struct nn_ep *self); |
||||
|
void nn_ep_getopt(struct nn_ep *self,int32_t level,int32_t option,void *optval, size_t *optvallen); |
||||
|
int nn_ep_ispeer (struct nn_ep *self,int32_t socktype); |
||||
|
//void nn_ep_set_error(struct nn_ep *self,int32_t errnum);
|
||||
|
void nn_ep_set_error(struct nn_ep *self,int32_t errnum,char *fname,int32_t linenum); |
||||
|
void nn_ep_clear_error(struct nn_ep *self); |
||||
|
void nn_ep_stat_increment(struct nn_ep *self,int32_t name,int32_t increment); |
||||
|
|
||||
|
#endif |
@ -0,0 +1,76 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../transport.h" |
||||
|
|
||||
|
#include "ep.h" |
||||
|
#include "sock.h" |
||||
|
#include "../utils/attr.h" |
||||
|
|
||||
|
void nn_epbase_init (struct nn_epbase *self,const struct nn_epbase_vfptr *vfptr, void *hint) |
||||
|
{ |
||||
|
self->vfptr = vfptr; |
||||
|
self->ep = (struct nn_ep*) hint; |
||||
|
} |
||||
|
|
||||
|
void nn_epbase_term (NN_UNUSED struct nn_epbase *self) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
void nn_epbase_stopped (struct nn_epbase *self) |
||||
|
{ |
||||
|
nn_ep_stopped (self->ep); |
||||
|
} |
||||
|
|
||||
|
struct nn_ctx *nn_epbase_getctx (struct nn_epbase *self) |
||||
|
{ |
||||
|
return nn_ep_getctx (self->ep); |
||||
|
} |
||||
|
|
||||
|
const char *nn_epbase_getaddr (struct nn_epbase *self) |
||||
|
{ |
||||
|
return nn_ep_getaddr (self->ep); |
||||
|
} |
||||
|
|
||||
|
void nn_epbase_getopt(struct nn_epbase *self,int32_t level,int32_t option,void *optval,size_t *optvallen) |
||||
|
{ |
||||
|
nn_ep_getopt (self->ep, level, option, optval, optvallen); |
||||
|
} |
||||
|
|
||||
|
int nn_epbase_ispeer(struct nn_epbase *self,int32_t socktype) |
||||
|
{ |
||||
|
return nn_ep_ispeer (self->ep, socktype); |
||||
|
} |
||||
|
|
||||
|
void nn_epbase_set_error(struct nn_epbase *self,int32_t errnum,char *fname,int32_t linenum) |
||||
|
{ |
||||
|
nn_ep_set_error(self->ep,errnum,fname,linenum); |
||||
|
} |
||||
|
|
||||
|
void nn_epbase_clear_error (struct nn_epbase *self) |
||||
|
{ |
||||
|
nn_ep_clear_error (self->ep); |
||||
|
} |
||||
|
|
||||
|
void nn_epbase_stat_increment(struct nn_epbase *self, int name, int increment) { |
||||
|
nn_ep_stat_increment(self->ep, name, increment); |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,33 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_GLOBAL_INCLUDED |
||||
|
#define NN_GLOBAL_INCLUDED |
||||
|
|
||||
|
/* Provides access to the list of available transports. */ |
||||
|
struct nn_transport *nn_global_transport (int id); |
||||
|
|
||||
|
/* Returns the global worker thread pool. */ |
||||
|
struct nn_pool *nn_global_getpool (); |
||||
|
int nn_global_print_errors(); |
||||
|
|
||||
|
#endif |
@ -0,0 +1,218 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../transport.h" |
||||
|
#include "../protocol.h" |
||||
|
|
||||
|
#include "sock.h" |
||||
|
#include "ep.h" |
||||
|
|
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/fast.h" |
||||
|
|
||||
|
/* Internal pipe states. */ |
||||
|
#define NN_PIPEBASE_STATE_IDLE 1 |
||||
|
#define NN_PIPEBASE_STATE_ACTIVE 2 |
||||
|
#define NN_PIPEBASE_STATE_FAILED 3 |
||||
|
|
||||
|
#define NN_PIPEBASE_INSTATE_DEACTIVATED 0 |
||||
|
#define NN_PIPEBASE_INSTATE_IDLE 1 |
||||
|
#define NN_PIPEBASE_INSTATE_RECEIVING 2 |
||||
|
#define NN_PIPEBASE_INSTATE_RECEIVED 3 |
||||
|
#define NN_PIPEBASE_INSTATE_ASYNC 4 |
||||
|
|
||||
|
#define NN_PIPEBASE_OUTSTATE_DEACTIVATED 0 |
||||
|
#define NN_PIPEBASE_OUTSTATE_IDLE 1 |
||||
|
#define NN_PIPEBASE_OUTSTATE_SENDING 2 |
||||
|
#define NN_PIPEBASE_OUTSTATE_SENT 3 |
||||
|
#define NN_PIPEBASE_OUTSTATE_ASYNC 4 |
||||
|
|
||||
|
void nn_pipebase_init(struct nn_pipebase *self,const struct nn_pipebase_vfptr *vfptr,struct nn_epbase *epbase) |
||||
|
{ |
||||
|
nn_assert (epbase->ep->sock); |
||||
|
nn_fsm_init(&self->fsm,NULL,NULL,0,self,&epbase->ep->sock->fsm); |
||||
|
self->vfptr = vfptr; |
||||
|
self->state = NN_PIPEBASE_STATE_IDLE; |
||||
|
self->instate = NN_PIPEBASE_INSTATE_DEACTIVATED; |
||||
|
self->outstate = NN_PIPEBASE_OUTSTATE_DEACTIVATED; |
||||
|
self->sock = epbase->ep->sock; |
||||
|
memcpy(&self->options,&epbase->ep->options,sizeof(struct nn_ep_options)); |
||||
|
nn_fsm_event_init(&self->in); |
||||
|
nn_fsm_event_init(&self->out); |
||||
|
//printf("pipebase_init vfptr.%p recv.%p rcvprio.%d\n",vfptr,vfptr->recv,self->options.rcvprio);
|
||||
|
} |
||||
|
|
||||
|
void nn_pipebase_term (struct nn_pipebase *self) |
||||
|
{ |
||||
|
nn_assert_state (self, NN_PIPEBASE_STATE_IDLE); |
||||
|
|
||||
|
nn_fsm_event_term (&self->out); |
||||
|
nn_fsm_event_term (&self->in); |
||||
|
nn_fsm_term (&self->fsm); |
||||
|
} |
||||
|
|
||||
|
int nn_pipebase_start (struct nn_pipebase *self) |
||||
|
{ |
||||
|
int rc; |
||||
|
nn_assert_state (self,NN_PIPEBASE_STATE_IDLE); |
||||
|
self->state = NN_PIPEBASE_STATE_ACTIVE; |
||||
|
self->instate = NN_PIPEBASE_INSTATE_ASYNC; |
||||
|
self->outstate = NN_PIPEBASE_OUTSTATE_IDLE; |
||||
|
rc = nn_sock_add(self->sock,(struct nn_pipe *)self); |
||||
|
//printf("nn_pipebase_start self.%p rc.%d\n",self,rc);
|
||||
|
if ( nn_slow(rc < 0) ) |
||||
|
{ |
||||
|
self->state = NN_PIPEBASE_STATE_FAILED; |
||||
|
return rc; |
||||
|
} |
||||
|
if ( self->sock ) |
||||
|
nn_fsm_raise(&self->fsm,&self->out,NN_PIPE_OUT); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void nn_pipebase_stop(struct nn_pipebase *self) |
||||
|
{ |
||||
|
if (self->state == NN_PIPEBASE_STATE_ACTIVE) |
||||
|
nn_sock_rm (self->sock, (struct nn_pipe*) self); |
||||
|
self->state = NN_PIPEBASE_STATE_IDLE; |
||||
|
} |
||||
|
|
||||
|
void nn_pipebase_received(struct nn_pipebase *self) |
||||
|
{ |
||||
|
//printf("nn_pipebase_received\n");
|
||||
|
if ( nn_fast(self->instate == NN_PIPEBASE_INSTATE_RECEIVING) ) |
||||
|
{ |
||||
|
self->instate = NN_PIPEBASE_INSTATE_RECEIVED; |
||||
|
return; |
||||
|
} |
||||
|
nn_assert (self->instate == NN_PIPEBASE_INSTATE_ASYNC); |
||||
|
self->instate = NN_PIPEBASE_INSTATE_IDLE; |
||||
|
if ( self->sock ) |
||||
|
nn_fsm_raise(&self->fsm,&self->in,NN_PIPE_IN); |
||||
|
} |
||||
|
|
||||
|
void nn_pipebase_sent(struct nn_pipebase *self) |
||||
|
{ |
||||
|
if ( nn_fast(self->outstate == NN_PIPEBASE_OUTSTATE_SENDING) ) |
||||
|
{ |
||||
|
self->outstate = NN_PIPEBASE_OUTSTATE_SENT; |
||||
|
return; |
||||
|
} |
||||
|
nn_assert (self->outstate == NN_PIPEBASE_OUTSTATE_ASYNC); |
||||
|
self->outstate = NN_PIPEBASE_OUTSTATE_IDLE; |
||||
|
if ( self->sock ) |
||||
|
nn_fsm_raise(&self->fsm,&self->out,NN_PIPE_OUT); |
||||
|
} |
||||
|
|
||||
|
void nn_pipebase_getopt(struct nn_pipebase *self, int level, int option,void *optval, size_t *optvallen) |
||||
|
{ |
||||
|
int rc,intval; |
||||
|
|
||||
|
if ( level == NN_SOL_SOCKET ) |
||||
|
{ |
||||
|
switch (option) |
||||
|
{ |
||||
|
/* Endpoint options */ |
||||
|
case NN_SNDPRIO: |
||||
|
intval = self->options.sndprio; |
||||
|
break; |
||||
|
case NN_RCVPRIO: |
||||
|
intval = self->options.rcvprio; |
||||
|
break; |
||||
|
case NN_IPV4ONLY: |
||||
|
intval = self->options.ipv4only; |
||||
|
break; |
||||
|
|
||||
|
/* Fallback to socket options */ |
||||
|
default: |
||||
|
rc = nn_sock_getopt_inner(self->sock, level,option, optval, optvallen); |
||||
|
errnum_assert (rc == 0, -rc); |
||||
|
return; |
||||
|
} |
||||
|
memcpy (optval, &intval,*optvallen < sizeof (int) ? *optvallen : sizeof (int)); |
||||
|
*optvallen = sizeof (int); |
||||
|
return; |
||||
|
} |
||||
|
rc = nn_sock_getopt_inner (self->sock, level, option, optval, optvallen); |
||||
|
errnum_assert (rc == 0, -rc); |
||||
|
} |
||||
|
|
||||
|
int nn_pipebase_ispeer(struct nn_pipebase *self,int socktype) |
||||
|
{ |
||||
|
return nn_sock_ispeer (self->sock, socktype); |
||||
|
} |
||||
|
|
||||
|
void nn_pipe_setdata(struct nn_pipe *self,void *data) |
||||
|
{ |
||||
|
((struct nn_pipebase *)self)->data = data; |
||||
|
} |
||||
|
|
||||
|
void *nn_pipe_getdata(struct nn_pipe *self) |
||||
|
{ |
||||
|
return ((struct nn_pipebase *)self)->data; |
||||
|
} |
||||
|
|
||||
|
int nn_pipe_send(struct nn_pipe *self,struct nn_msg *msg) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct nn_pipebase *pipebase; |
||||
|
pipebase = (struct nn_pipebase *)self; |
||||
|
nn_assert (pipebase->outstate == NN_PIPEBASE_OUTSTATE_IDLE); |
||||
|
pipebase->outstate = NN_PIPEBASE_OUTSTATE_SENDING; |
||||
|
rc = pipebase->vfptr->send(pipebase,msg); |
||||
|
errnum_assert (rc >= 0, -rc); |
||||
|
if ( nn_fast(pipebase->outstate == NN_PIPEBASE_OUTSTATE_SENT) ) |
||||
|
{ |
||||
|
pipebase->outstate = NN_PIPEBASE_OUTSTATE_IDLE; |
||||
|
return rc; |
||||
|
} |
||||
|
nn_assert(pipebase->outstate == NN_PIPEBASE_OUTSTATE_SENDING); |
||||
|
pipebase->outstate = NN_PIPEBASE_OUTSTATE_ASYNC; |
||||
|
return rc | NN_PIPEBASE_RELEASE; |
||||
|
} |
||||
|
|
||||
|
int nn_pipe_recv(struct nn_pipe *self,struct nn_msg *msg) |
||||
|
{ |
||||
|
int rc; struct nn_pipebase *pipebase; |
||||
|
pipebase = (struct nn_pipebase*) self; |
||||
|
nn_assert (pipebase->instate == NN_PIPEBASE_INSTATE_IDLE); |
||||
|
pipebase->instate = NN_PIPEBASE_INSTATE_RECEIVING; |
||||
|
//printf("call pipebase recv\n");
|
||||
|
rc = pipebase->vfptr->recv (pipebase,msg); |
||||
|
errnum_assert (rc >= 0, -rc); |
||||
|
if ( nn_fast(pipebase->instate == NN_PIPEBASE_INSTATE_RECEIVED) ) |
||||
|
{ |
||||
|
pipebase->instate = NN_PIPEBASE_INSTATE_IDLE; |
||||
|
return rc; |
||||
|
} |
||||
|
nn_assert(pipebase->instate == NN_PIPEBASE_INSTATE_RECEIVING); |
||||
|
pipebase->instate = NN_PIPEBASE_INSTATE_ASYNC; |
||||
|
return rc | NN_PIPEBASE_RELEASE; |
||||
|
} |
||||
|
|
||||
|
void nn_pipe_getopt(struct nn_pipe *self,int level,int option,void *optval,size_t *optvallen) |
||||
|
{ |
||||
|
struct nn_pipebase *pipebase; |
||||
|
pipebase = (struct nn_pipebase *)self; |
||||
|
nn_pipebase_getopt(pipebase,level,option,optval,optvallen); |
||||
|
} |
||||
|
|
@ -0,0 +1,205 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../nn.h" |
||||
|
|
||||
|
#if defined NN_HAVE_WINDOWS |
||||
|
|
||||
|
#include "../utils/win.h" |
||||
|
#include "../utils/fast.h" |
||||
|
#include "../utils/sleep.h" |
||||
|
#include "../utils/err.h" |
||||
|
|
||||
|
int nn_poll (struct nn_pollfd *fds, int nfds, int timeout) |
||||
|
{ |
||||
|
int rc; |
||||
|
int i; |
||||
|
fd_set fdset; |
||||
|
SOCKET fd; |
||||
|
int res; |
||||
|
size_t sz; |
||||
|
struct timeval tv; |
||||
|
|
||||
|
/* Fill in the fdset, as appropriate. */ |
||||
|
FD_ZERO (&fdset); |
||||
|
for (i = 0; i != nfds; ++i) { |
||||
|
if (fds [i].events & NN_POLLIN) { |
||||
|
sz = sizeof (fd); |
||||
|
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz); |
||||
|
if (nn_slow (rc < 0)) { |
||||
|
errno = -rc; |
||||
|
return -1; |
||||
|
} |
||||
|
nn_assert (sz == sizeof (fd)); |
||||
|
FD_SET (fd, &fdset); |
||||
|
} |
||||
|
if (fds [i].events & NN_POLLOUT) { |
||||
|
sz = sizeof (fd); |
||||
|
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_SNDFD, &fd, &sz); |
||||
|
if (nn_slow (rc < 0)) { |
||||
|
errno = -rc; |
||||
|
return -1; |
||||
|
} |
||||
|
nn_assert (sz == sizeof (fd)); |
||||
|
FD_SET (fd, &fdset); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Do the polling itself. */ |
||||
|
tv.tv_sec = timeout / 1000; |
||||
|
tv.tv_usec = timeout % 1000 * 1000; |
||||
|
if (nn_fast (nfds)) { |
||||
|
rc = select (-1, &fdset, NULL, NULL, &tv); |
||||
|
if (nn_slow (rc == 0)) |
||||
|
return 0; |
||||
|
if (nn_slow (rc == SOCKET_ERROR)) { |
||||
|
errno = nn_err_wsa_to_posix (WSAGetLastError ()); |
||||
|
return -1; |
||||
|
} |
||||
|
} |
||||
|
else { |
||||
|
|
||||
|
// POSIX platforms will sleep until timeout is expired,
|
||||
|
// so let's do the same on Windows.
|
||||
|
if (timeout > 0) |
||||
|
nn_sleep(timeout); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
/* Move the results from fdset to the nanomsg pollset. */ |
||||
|
res = 0; |
||||
|
for (i = 0; i != nfds; ++i) { |
||||
|
fds [i].revents = 0; |
||||
|
if (fds [i].events & NN_POLLIN) { |
||||
|
sz = sizeof (fd); |
||||
|
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz); |
||||
|
if (nn_slow (rc < 0)) { |
||||
|
errno = -rc; |
||||
|
return -1; |
||||
|
} |
||||
|
nn_assert (sz == sizeof (fd)); |
||||
|
if (FD_ISSET (fd, &fdset)) |
||||
|
fds [i].revents |= NN_POLLIN; |
||||
|
} |
||||
|
if (fds [i].events & NN_POLLOUT) { |
||||
|
sz = sizeof (fd); |
||||
|
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_SNDFD, &fd, &sz); |
||||
|
if (nn_slow (rc < 0)) { |
||||
|
errno = -rc; |
||||
|
return -1; |
||||
|
} |
||||
|
nn_assert (sz == sizeof (fd)); |
||||
|
if (FD_ISSET (fd, &fdset)) |
||||
|
fds [i].revents |= NN_POLLOUT; |
||||
|
} |
||||
|
if (fds [i].revents) |
||||
|
++res; |
||||
|
} |
||||
|
|
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
#else |
||||
|
|
||||
|
#include "../utils/alloc.h" |
||||
|
#include "../utils/fast.h" |
||||
|
#include "../utils/err.h" |
||||
|
|
||||
|
#include <poll.h> |
||||
|
#include <stddef.h> |
||||
|
|
||||
|
int nn_poll (struct nn_pollfd *fds, int nfds, int timeout) |
||||
|
{ |
||||
|
int rc; |
||||
|
int i; |
||||
|
int pos; |
||||
|
int fd; |
||||
|
int res; |
||||
|
size_t sz; |
||||
|
struct pollfd *pfd; |
||||
|
|
||||
|
/* Construct a pollset to be used with OS-level 'poll' function. */ |
||||
|
pfd = nn_alloc (sizeof (struct pollfd) * nfds * 2, "pollset"); |
||||
|
alloc_assert (pfd); |
||||
|
pos = 0; |
||||
|
for (i = 0; i != nfds; ++i) { |
||||
|
if (fds [i].events & NN_POLLIN) { |
||||
|
sz = sizeof (fd); |
||||
|
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz); |
||||
|
if (nn_slow (rc < 0)) { |
||||
|
nn_free (pfd); |
||||
|
errno = -rc; |
||||
|
return -1; |
||||
|
} |
||||
|
nn_assert (sz == sizeof (fd)); |
||||
|
pfd [pos].fd = fd; |
||||
|
pfd [pos].events = POLLIN; |
||||
|
++pos; |
||||
|
} |
||||
|
if (fds [i].events & NN_POLLOUT) { |
||||
|
sz = sizeof (fd); |
||||
|
rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_SNDFD, &fd, &sz); |
||||
|
if (nn_slow (rc < 0)) { |
||||
|
nn_free (pfd); |
||||
|
errno = -rc; |
||||
|
return -1; |
||||
|
} |
||||
|
nn_assert (sz == sizeof (fd)); |
||||
|
pfd [pos].fd = fd; |
||||
|
pfd [pos].events = POLLIN; |
||||
|
++pos; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Do the polling itself. */ |
||||
|
rc = poll (pfd, pos, timeout); |
||||
|
if (nn_slow (rc <= 0)) { |
||||
|
res = errno; |
||||
|
nn_free (pfd); |
||||
|
errno = res; |
||||
|
return rc; |
||||
|
} |
||||
|
|
||||
|
/* Move the results from OS-level poll to nn_poll's pollset. */ |
||||
|
res = 0; |
||||
|
pos = 0; |
||||
|
for (i = 0; i != nfds; ++i) { |
||||
|
fds [i].revents = 0; |
||||
|
if (fds [i].events & NN_POLLIN) { |
||||
|
if (pfd [pos].revents & POLLIN) |
||||
|
fds [i].revents |= NN_POLLIN; |
||||
|
++pos; |
||||
|
} |
||||
|
if (fds [i].events & NN_POLLOUT) { |
||||
|
if (pfd [pos].revents & POLLIN) |
||||
|
fds [i].revents |= NN_POLLOUT; |
||||
|
++pos; |
||||
|
} |
||||
|
if (fds [i].revents) |
||||
|
++res; |
||||
|
} |
||||
|
|
||||
|
nn_free (pfd); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
#endif |
File diff suppressed because it is too large
@ -0,0 +1,196 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_SOCK_INCLUDED |
||||
|
#define NN_SOCK_INCLUDED |
||||
|
|
||||
|
#include "../protocol.h" |
||||
|
#include "../transport.h" |
||||
|
|
||||
|
#include "../aio/ctx.h" |
||||
|
#include "../aio/fsm.h" |
||||
|
|
||||
|
#include "../utils/efd.h" |
||||
|
#include "../utils/sem.h" |
||||
|
#include "../utils/clock.h" |
||||
|
#include "../utils/list.h" |
||||
|
|
||||
|
struct nn_pipe; |
||||
|
|
||||
|
/* The maximum implemented transport ID. */ |
||||
|
#define NN_MAX_TRANSPORT 4 |
||||
|
|
||||
|
/* The socket-internal statistics */ |
||||
|
#define NN_STAT_MESSAGES_SENT 301 |
||||
|
#define NN_STAT_MESSAGES_RECEIVED 302 |
||||
|
#define NN_STAT_BYTES_SENT 303 |
||||
|
#define NN_STAT_BYTES_RECEIVED 304 |
||||
|
|
||||
|
|
||||
|
struct nn_sock |
||||
|
{ |
||||
|
/* Socket state machine. */ |
||||
|
struct nn_fsm fsm; |
||||
|
int state; |
||||
|
|
||||
|
/* Pointer to the instance of the specific socket type. */ |
||||
|
struct nn_sockbase *sockbase; |
||||
|
|
||||
|
/* Pointer to the socket type metadata. */ |
||||
|
struct nn_socktype *socktype; |
||||
|
|
||||
|
int flags; |
||||
|
|
||||
|
struct nn_ctx ctx; |
||||
|
struct nn_efd sndfd; |
||||
|
struct nn_efd rcvfd; |
||||
|
struct nn_sem termsem; |
||||
|
|
||||
|
/* TODO: This clock can be accessed from different threads. If RDTSC
|
||||
|
is out-of-sync among different CPU cores, this can be a problem. */ |
||||
|
struct nn_clock clock; |
||||
|
|
||||
|
/* List of all endpoints associated with the socket. */ |
||||
|
struct nn_list eps; |
||||
|
|
||||
|
/* List of all endpoint being in the process of shutting down. */ |
||||
|
struct nn_list sdeps; |
||||
|
|
||||
|
/* Next endpoint ID to assign to a new endpoint. */ |
||||
|
int eid; |
||||
|
|
||||
|
/* Socket-level socket options. */ |
||||
|
int linger; |
||||
|
int sndbuf; |
||||
|
int rcvbuf; |
||||
|
int rcvmaxsize; |
||||
|
int sndtimeo; |
||||
|
int rcvtimeo; |
||||
|
int reconnect_ivl; |
||||
|
int reconnect_ivl_max; |
||||
|
|
||||
|
/* Endpoint-specific options. */ |
||||
|
struct nn_ep_options ep_template; |
||||
|
|
||||
|
/* Transport-specific socket options. */ |
||||
|
struct nn_optset *optsets [NN_MAX_TRANSPORT]; |
||||
|
|
||||
|
struct { |
||||
|
|
||||
|
/***** The ever-incrementing counters *****/ |
||||
|
|
||||
|
/* Successfully established nn_connect() connections */ |
||||
|
uint64_t established_connections; |
||||
|
/* Successfully accepted connections */ |
||||
|
uint64_t accepted_connections; |
||||
|
/* Forcedly closed connections */ |
||||
|
uint64_t dropped_connections; |
||||
|
/* Connections closed by peer */ |
||||
|
uint64_t broken_connections; |
||||
|
/* Errors trying to establish active connection */ |
||||
|
uint64_t connect_errors; |
||||
|
/* Errors binding to specified port */ |
||||
|
uint64_t bind_errors; |
||||
|
/* Errors accepting connections at nn_bind()'ed endpoint */ |
||||
|
uint64_t accept_errors; |
||||
|
|
||||
|
/* Messages sent */ |
||||
|
uint64_t messages_sent; |
||||
|
/* Messages received */ |
||||
|
uint64_t messages_received; |
||||
|
/* Bytes sent (sum length of data in messages sent) */ |
||||
|
uint64_t bytes_sent; |
||||
|
/* Bytes recevied (sum length of data in messages received) */ |
||||
|
uint64_t bytes_received; |
||||
|
|
||||
|
/***** Level-style values *****/ |
||||
|
|
||||
|
/* Number of currently established connections */ |
||||
|
int current_connections; |
||||
|
/* Number of connections currently in progress */ |
||||
|
int inprogress_connections; |
||||
|
/* The currently set priority for sending data */ |
||||
|
int current_snd_priority; |
||||
|
/* Number of endpoints having last_errno set to non-zero value */ |
||||
|
int current_ep_errors; |
||||
|
|
||||
|
} statistics; |
||||
|
|
||||
|
/* The socket name for statistics */ |
||||
|
char socket_name[64]; |
||||
|
}; |
||||
|
|
||||
|
/* Initialise the socket. */ |
||||
|
int nn_sock_init (struct nn_sock *self, struct nn_socktype *socktype, int fd); |
||||
|
|
||||
|
/* Called by nn_close() to deallocate the socket. It's a blocking function
|
||||
|
and can return -EINTR. */ |
||||
|
int nn_sock_term (struct nn_sock *self); |
||||
|
|
||||
|
/* Called by sockbase when stopping is done. */ |
||||
|
void nn_sock_stopped (struct nn_sock *self); |
||||
|
|
||||
|
/* Called by nn_term() to let the socket know about the process shutdown. */ |
||||
|
void nn_sock_zombify (struct nn_sock *self); |
||||
|
|
||||
|
/* Returns the AIO context associated with the socket. */ |
||||
|
struct nn_ctx *nn_sock_getctx (struct nn_sock *self); |
||||
|
|
||||
|
/* Returns 1 if the specified socket type is a valid peer for this socket,
|
||||
|
0 otherwise. */ |
||||
|
int nn_sock_ispeer (struct nn_sock *self, int socktype); |
||||
|
|
||||
|
struct nn_ep *nn_find_ep(struct nn_sock *self,int32_t eid,const char *addr,struct nn_transport *transport,int32_t bind); |
||||
|
|
||||
|
/* Add new endpoint to the socket. */ |
||||
|
int nn_sock_add_ep (struct nn_sock *self, struct nn_transport *transport,int bind, const char *addr); |
||||
|
|
||||
|
/* Remove the endpoint with the specified ID from the socket. */ |
||||
|
int nn_sock_rm_ep (struct nn_sock *self, int eid); |
||||
|
|
||||
|
/* Send a message to the socket. */ |
||||
|
int nn_sock_send (struct nn_sock *self, struct nn_msg *msg, int flags); |
||||
|
|
||||
|
/* Receive a message from the socket. */ |
||||
|
int nn_sock_recv (struct nn_sock *self, struct nn_msg *msg, int flags); |
||||
|
|
||||
|
/* Set a socket option. */ |
||||
|
int nn_sock_setopt (struct nn_sock *self, int level, int option,const void *optval, size_t optvallen); |
||||
|
|
||||
|
/* Retrieve a socket option. This function is to be called from the API. */ |
||||
|
int nn_sock_getopt (struct nn_sock *self, int level, int option,void *optval, size_t *optvallen); |
||||
|
|
||||
|
/* Retrieve a socket option. This function is to be called from within
|
||||
|
the socket. */ |
||||
|
int nn_sock_getopt_inner (struct nn_sock *self, int level, int option,void *optval, size_t *optvallen); |
||||
|
|
||||
|
/* Used by pipes. */ |
||||
|
int nn_sock_add (struct nn_sock *self, struct nn_pipe *pipe); |
||||
|
void nn_sock_rm (struct nn_sock *self, struct nn_pipe *pipe); |
||||
|
|
||||
|
/* Monitoring callbacks */ |
||||
|
//void nn_sock_report_error(struct nn_sock *self, struct nn_ep *ep, int errnum);
|
||||
|
void nn_sock_report_error(struct nn_sock *self,struct nn_ep *ep,int32_t errnum,char *fname,int32_t linenum); |
||||
|
void nn_sock_stat_increment(struct nn_sock *self, int name, int64_t increment); |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,58 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../protocol.h" |
||||
|
|
||||
|
#include "sock.h" |
||||
|
|
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/attr.h" |
||||
|
|
||||
|
void nn_sockbase_init(struct nn_sockbase *self,const struct nn_sockbase_vfptr *vfptr,void *hint) |
||||
|
{ |
||||
|
self->vfptr = vfptr; |
||||
|
self->sock = (struct nn_sock*) hint; |
||||
|
} |
||||
|
|
||||
|
void nn_sockbase_term(NN_UNUSED struct nn_sockbase *self) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
void nn_sockbase_stopped(struct nn_sockbase *self) |
||||
|
{ |
||||
|
nn_sock_stopped(self->sock); |
||||
|
} |
||||
|
|
||||
|
struct nn_ctx *nn_sockbase_getctx(struct nn_sockbase *self) |
||||
|
{ |
||||
|
return nn_sock_getctx (self->sock); |
||||
|
} |
||||
|
|
||||
|
int32_t nn_sockbase_getopt(struct nn_sockbase *self,int32_t option,void *optval,size_t *optvallen) |
||||
|
{ |
||||
|
return nn_sock_getopt_inner(self->sock,NN_SOL_SOCKET,option,optval,optvallen); |
||||
|
} |
||||
|
|
||||
|
void nn_sockbase_stat_increment(struct nn_sockbase *self,int32_t name,int32_t increment) |
||||
|
{ |
||||
|
nn_sock_stat_increment(self->sock, name, increment); |
||||
|
} |
@ -0,0 +1,246 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Evan Wies <evan@neomantra.net> |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../nn.h" |
||||
|
|
||||
|
#include "../inproc.h" |
||||
|
#include "../ipc.h" |
||||
|
#include "../tcp.h" |
||||
|
|
||||
|
#include "../pair.h" |
||||
|
#include "../pubsub.h" |
||||
|
#include "../reqrep.h" |
||||
|
#include "../pipeline.h" |
||||
|
#include "../survey.h" |
||||
|
#include "../bus.h" |
||||
|
|
||||
|
#include <string.h> |
||||
|
|
||||
|
static const struct nn_symbol_properties sym_value_names [] = { |
||||
|
{NN_NS_NAMESPACE, "NN_NS_NAMESPACE", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_VERSION, "NN_NS_VERSION", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_DOMAIN, "NN_NS_DOMAIN", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_TRANSPORT, "NN_NS_TRANSPORT", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_PROTOCOL, "NN_NS_PROTOCOL", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_OPTION_LEVEL, "NN_NS_OPTION_LEVEL", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_SOCKET_OPTION, "NN_NS_SOCKET_OPTION", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_TRANSPORT_OPTION, "NN_NS_TRANSPORT_OPTION", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_OPTION_TYPE, "NN_NS_OPTION_TYPE", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_OPTION_UNIT, "NN_NS_OPTION_UNIT", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_FLAG, "NN_NS_FLAG", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_ERROR, "NN_NS_ERROR", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_LIMIT, "NN_NS_LIMIT", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_NS_EVENT, "NN_NS_EVENT", NN_NS_NAMESPACE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_TYPE_NONE, "NN_TYPE_NONE", NN_NS_OPTION_TYPE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_TYPE_INT, "NN_TYPE_INT", NN_NS_OPTION_TYPE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_TYPE_STR, "NN_TYPE_STR", NN_NS_OPTION_TYPE, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_UNIT_NONE, "NN_UNIT_NONE", NN_NS_OPTION_UNIT, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_UNIT_BYTES, "NN_UNIT_BYTES", NN_NS_OPTION_UNIT, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_UNIT_MILLISECONDS, "NN_UNIT_MILLISECONDS", NN_NS_OPTION_UNIT, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_UNIT_PRIORITY, "NN_UNIT_PRIORITY", NN_NS_OPTION_UNIT, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_UNIT_BOOLEAN, "NN_UNIT_BOOLEAN", NN_NS_OPTION_UNIT, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_VERSION_CURRENT, "NN_VERSION_CURRENT", NN_NS_VERSION, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_VERSION_REVISION, "NN_VERSION_REVISION", NN_NS_VERSION, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_VERSION_AGE, "NN_VERSION_AGE", NN_NS_VERSION, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{AF_SP, "AF_SP", NN_NS_DOMAIN, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{AF_SP_RAW, "AF_SP_RAW", NN_NS_DOMAIN, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_INPROC, "NN_INPROC", NN_NS_TRANSPORT, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_IPC, "NN_IPC", NN_NS_TRANSPORT, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_TCP, "NN_TCP", NN_NS_TRANSPORT, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_PAIR, "NN_PAIR", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_PUB, "NN_PUB", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_SUB, "NN_SUB", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_REP, "NN_REP", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_REQ, "NN_REQ", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_PUSH, "NN_PUSH", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_PULL, "NN_PULL", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_SURVEYOR, "NN_SURVEYOR", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_RESPONDENT, "NN_RESPONDENT", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_BUS, "NN_BUS", NN_NS_PROTOCOL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_SOCKADDR_MAX, "NN_SOCKADDR_MAX", NN_NS_LIMIT, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_SOL_SOCKET, "NN_SOL_SOCKET", NN_NS_OPTION_LEVEL, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_LINGER, "NN_LINGER", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_MILLISECONDS}, |
||||
|
{NN_SNDBUF, "NN_SNDBUF", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_BYTES}, |
||||
|
{NN_RCVBUF, "NN_RCVBUF", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_BYTES}, |
||||
|
{NN_RCVMAXSIZE, "NN_RCVMAXSIZE", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_BYTES}, |
||||
|
{NN_SNDTIMEO, "NN_SNDTIMEO", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_MILLISECONDS}, |
||||
|
{NN_RCVTIMEO, "NN_RCVTIMEO", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_MILLISECONDS}, |
||||
|
{NN_RECONNECT_IVL, "NN_RECONNECT_IVL", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_MILLISECONDS}, |
||||
|
{NN_RECONNECT_IVL_MAX, "NN_RECONNECT_IVL_MAX", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_MILLISECONDS}, |
||||
|
{NN_SNDPRIO, "NN_SNDPRIO", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_PRIORITY}, |
||||
|
{NN_RCVPRIO, "NN_RCVPRIO", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_PRIORITY}, |
||||
|
{NN_SNDFD, "NN_SNDFD", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_NONE}, |
||||
|
{NN_RCVFD, "NN_RCVFD", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_NONE}, |
||||
|
{NN_DOMAIN, "NN_DOMAIN", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_NONE}, |
||||
|
{NN_PROTOCOL, "NN_PROTOCOL", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_NONE}, |
||||
|
{NN_IPV4ONLY, "NN_IPV4ONLY", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_BOOLEAN}, |
||||
|
{NN_SOCKET_NAME, "NN_SOCKET_NAME", NN_NS_SOCKET_OPTION, |
||||
|
NN_TYPE_STR, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_SUB_SUBSCRIBE, "NN_SUB_SUBSCRIBE", NN_NS_TRANSPORT_OPTION, |
||||
|
NN_TYPE_STR, NN_UNIT_NONE}, |
||||
|
{NN_SUB_UNSUBSCRIBE, "NN_SUB_UNSUBSCRIBE", NN_NS_TRANSPORT_OPTION, |
||||
|
NN_TYPE_STR, NN_UNIT_NONE}, |
||||
|
{NN_REQ_RESEND_IVL, "NN_REQ_RESEND_IVL", NN_NS_TRANSPORT_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_MILLISECONDS}, |
||||
|
{NN_SURVEYOR_DEADLINE, "NN_SURVEYOR_DEADLINE", NN_NS_TRANSPORT_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_MILLISECONDS}, |
||||
|
{NN_TCP_NODELAY, "NN_TCP_NODELAY", NN_NS_TRANSPORT_OPTION, |
||||
|
NN_TYPE_INT, NN_UNIT_BOOLEAN}, |
||||
|
|
||||
|
{NN_DONTWAIT, "NN_DONTWAIT", NN_NS_FLAG, |
||||
|
NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{NN_POLLIN, "NN_POLLIN", NN_NS_EVENT, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{NN_POLLOUT, "NN_POLLOUT", NN_NS_EVENT, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
|
||||
|
{EADDRINUSE, "EADDRINUSE", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EADDRNOTAVAIL, "EADDRNOTAVAIL", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EAFNOSUPPORT, "EAFNOSUPPORT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EAGAIN, "EAGAIN", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EBADF, "EBADF", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ECONNREFUSED, "ECONNREFUSED", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EFAULT, "EFAULT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EFSM, "EFSM", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EINPROGRESS, "EINPROGRESS", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EINTR, "EINTR", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EINVAL, "EINVAL", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EMFILE, "EMFILE", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENAMETOOLONG, "ENAMETOOLONG", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENETDOWN, "ENETDOWN", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENOBUFS, "ENOBUFS", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENODEV, "ENODEV", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENOMEM, "ENOMEM", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENOPROTOOPT, "ENOPROTOOPT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENOTSOCK, "ENOTSOCK", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENOTSUP, "ENOTSUP", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EPROTO, "EPROTO", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EPROTONOSUPPORT, "EPROTONOSUPPORT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ETERM, "ETERM", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ETIMEDOUT, "ETIMEDOUT", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EACCES, "EACCES" , NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ECONNABORTED, "ECONNABORTED", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ECONNRESET, "ECONNRESET", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EHOSTUNREACH, "EHOSTUNREACH", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{EMSGSIZE, "EMSGSIZE", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENETRESET, "ENETRESET", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENETUNREACH, "ENETUNREACH", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
{ENOTCONN, "ENOTCONN", NN_NS_ERROR, NN_TYPE_NONE, NN_UNIT_NONE}, |
||||
|
}; |
||||
|
|
||||
|
const int SYM_VALUE_NAMES_LEN = (sizeof (sym_value_names) / |
||||
|
sizeof (sym_value_names [0])); |
||||
|
|
||||
|
|
||||
|
const char *nn_symbol (int i, int *value) |
||||
|
{ |
||||
|
const struct nn_symbol_properties *svn; |
||||
|
if (i < 0 || i >= SYM_VALUE_NAMES_LEN) { |
||||
|
errno = EINVAL; |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
svn = &sym_value_names [i]; |
||||
|
if (value) |
||||
|
*value = svn->value; |
||||
|
return svn->name; |
||||
|
} |
||||
|
|
||||
|
int nn_symbol_info (int i, struct nn_symbol_properties *buf, int buflen) |
||||
|
{ |
||||
|
if (i < 0 || i >= SYM_VALUE_NAMES_LEN) { |
||||
|
return 0; |
||||
|
} |
||||
|
if (buflen > (int)sizeof (struct nn_symbol_properties)) { |
||||
|
buflen = (int)sizeof (struct nn_symbol_properties); |
||||
|
} |
||||
|
memcpy(buf, &sym_value_names [i], buflen); |
||||
|
return buflen; |
||||
|
} |
||||
|
|
@ -0,0 +1,396 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../nn.h" |
||||
|
|
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/fast.h" |
||||
|
#include "../utils/fd.h" |
||||
|
#include "../utils/attr.h" |
||||
|
#include "device.h" |
||||
|
|
||||
|
#include <string.h> |
||||
|
|
||||
|
#if defined NN_HAVE_WINDOWS |
||||
|
#include "../utils/win.h" |
||||
|
#elif defined NN_HAVE_POLL |
||||
|
#include <poll.h> |
||||
|
#else |
||||
|
#error |
||||
|
#endif |
||||
|
|
||||
|
int nn_custom_device(struct nn_device_recipe *device, int s1, int s2, |
||||
|
int flags) |
||||
|
{ |
||||
|
return nn_device_entry (device, s1, s2, flags); |
||||
|
} |
||||
|
|
||||
|
int nn_device (int s1, int s2) |
||||
|
{ |
||||
|
return nn_custom_device (&nn_ordinary_device, s1, s2, 0); |
||||
|
} |
||||
|
|
||||
|
int nn_device_entry (struct nn_device_recipe *device, int s1, int s2, |
||||
|
int flags) |
||||
|
{ |
||||
|
int rc; |
||||
|
int op1; |
||||
|
int op2; |
||||
|
nn_fd s1rcv; |
||||
|
nn_fd s1snd; |
||||
|
nn_fd s2rcv; |
||||
|
nn_fd s2snd; |
||||
|
size_t opsz; |
||||
|
|
||||
|
/* At least one socket must be specified. */ |
||||
|
if (device->required_checks & NN_CHECK_AT_LEAST_ONE_SOCKET) { |
||||
|
if (s1 < 0 && s2 < 0) { |
||||
|
errno = EBADF; |
||||
|
return -1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Handle the case when there's only one socket in the device. */ |
||||
|
if (device->required_checks & NN_CHECK_ALLOW_LOOPBACK) { |
||||
|
if (s2 < 0) |
||||
|
return nn_device_loopback (device,s1); |
||||
|
if (s1 < 0) |
||||
|
return nn_device_loopback (device,s2); |
||||
|
} |
||||
|
|
||||
|
/* Check whether both sockets are "raw" sockets. */ |
||||
|
if (device->required_checks & NN_CHECK_REQUIRE_RAW_SOCKETS) { |
||||
|
opsz = sizeof (op1); |
||||
|
rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_DOMAIN, &op1, &opsz); |
||||
|
errno_assert (rc == 0); |
||||
|
nn_assert (opsz == sizeof (op1)); |
||||
|
opsz = sizeof (op2); |
||||
|
rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_DOMAIN, &op2, &opsz); |
||||
|
errno_assert (rc == 0); |
||||
|
nn_assert (opsz == sizeof (op2)); |
||||
|
if (op1 != AF_SP_RAW || op2 != AF_SP_RAW) { |
||||
|
errno = EINVAL; |
||||
|
return -1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Check whether both sockets are from the same protocol. */ |
||||
|
if (device->required_checks & NN_CHECK_SAME_PROTOCOL_FAMILY) { |
||||
|
opsz = sizeof (op1); |
||||
|
rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_PROTOCOL, &op1, &opsz); |
||||
|
errno_assert (rc == 0); |
||||
|
nn_assert (opsz == sizeof (op1)); |
||||
|
opsz = sizeof (op2); |
||||
|
rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_PROTOCOL, &op2, &opsz); |
||||
|
errno_assert (rc == 0); |
||||
|
nn_assert (opsz == sizeof (op2)); |
||||
|
if (op1 / 16 != op2 / 16) { |
||||
|
errno = EINVAL; |
||||
|
return -1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Get the file descriptors for polling. */ |
||||
|
opsz = sizeof (s1rcv); |
||||
|
rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_RCVFD, &s1rcv, &opsz); |
||||
|
if (rc < 0 && nn_errno () == ENOPROTOOPT) |
||||
|
s1rcv = -1; |
||||
|
else { |
||||
|
nn_assert (rc == 0); |
||||
|
nn_assert (opsz == sizeof (s1rcv)); |
||||
|
nn_assert (s1rcv >= 0); |
||||
|
} |
||||
|
opsz = sizeof (s1snd); |
||||
|
rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_SNDFD, &s1snd, &opsz); |
||||
|
if (rc < 0 && nn_errno () == ENOPROTOOPT) |
||||
|
s1snd = -1; |
||||
|
else { |
||||
|
nn_assert (rc == 0); |
||||
|
nn_assert (opsz == sizeof (s1snd)); |
||||
|
nn_assert (s1snd >= 0); |
||||
|
} |
||||
|
opsz = sizeof (s2rcv); |
||||
|
rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_RCVFD, &s2rcv, &opsz); |
||||
|
if (rc < 0 && nn_errno () == ENOPROTOOPT) |
||||
|
s2rcv = -1; |
||||
|
else { |
||||
|
nn_assert (rc == 0); |
||||
|
nn_assert (opsz == sizeof (s2rcv)); |
||||
|
nn_assert (s2rcv >= 0); |
||||
|
} |
||||
|
opsz = sizeof (s2snd); |
||||
|
rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_SNDFD, &s2snd, &opsz); |
||||
|
if (rc < 0 && nn_errno () == ENOPROTOOPT) |
||||
|
s2snd = -1; |
||||
|
else { |
||||
|
nn_assert (rc == 0); |
||||
|
nn_assert (opsz == sizeof (s2snd)); |
||||
|
nn_assert (s2snd >= 0); |
||||
|
} |
||||
|
if (device->required_checks & NN_CHECK_SOCKET_DIRECTIONALITY) { |
||||
|
/* Check the directionality of the sockets. */ |
||||
|
if (s1rcv != -1 && s2snd == -1) { |
||||
|
errno = EINVAL; |
||||
|
return -1; |
||||
|
} |
||||
|
if (s1snd != -1 && s2rcv == -1) { |
||||
|
errno = EINVAL; |
||||
|
return -1; |
||||
|
} |
||||
|
if (s2rcv != -1 && s1snd == -1) { |
||||
|
errno = EINVAL; |
||||
|
return -1; |
||||
|
} |
||||
|
if (s2snd != -1 && s1rcv == -1) { |
||||
|
errno = EINVAL; |
||||
|
return -1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Two-directional device. */ |
||||
|
if (device->required_checks & NN_CHECK_ALLOW_BIDIRECTIONAL) { |
||||
|
if (s1rcv != -1 && s1snd != -1 && s2rcv != -1 && s2snd != -1) |
||||
|
return nn_device_twoway (device, s1, s1rcv, s1snd, |
||||
|
s2, s2rcv, s2snd); |
||||
|
} |
||||
|
|
||||
|
if (device->required_checks & NN_CHECK_ALLOW_UNIDIRECTIONAL) { |
||||
|
/* Single-directional device passing messages from s1 to s2. */ |
||||
|
if (s1rcv != -1 && s1snd == -1 && s2rcv == -1 && s2snd != -1) |
||||
|
return nn_device_oneway (device,s1, s1rcv, s2, s2snd); |
||||
|
|
||||
|
/* Single-directional device passing messages from s2 to s1. */ |
||||
|
if (s1rcv == -1 && s1snd != -1 && s2rcv != -1 && s2snd == -1) |
||||
|
return nn_device_oneway (device,s2, s2rcv, s1, s1snd); |
||||
|
} |
||||
|
|
||||
|
/* This should never happen. */ |
||||
|
nn_assert (0); |
||||
|
} |
||||
|
|
||||
|
int nn_device_loopback (struct nn_device_recipe *device, int s) |
||||
|
{ |
||||
|
int rc; |
||||
|
int op; |
||||
|
size_t opsz; |
||||
|
|
||||
|
/* Check whether the socket is a "raw" socket. */ |
||||
|
opsz = sizeof (op); |
||||
|
rc = nn_getsockopt (s, NN_SOL_SOCKET, NN_DOMAIN, &op, &opsz); |
||||
|
errno_assert (rc == 0); |
||||
|
nn_assert (opsz == sizeof (op)); |
||||
|
if (op != AF_SP_RAW) { |
||||
|
errno = EINVAL; |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
while (1) { |
||||
|
rc = nn_device_mvmsg (device,s, s, 0); |
||||
|
if (nn_slow (rc < 0)) |
||||
|
return -1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#if defined NN_HAVE_WINDOWS |
||||
|
|
||||
|
int nn_device_twoway (struct nn_device_recipe *device, |
||||
|
int s1, nn_fd s1rcv, nn_fd s1snd, |
||||
|
int s2, nn_fd s2rcv, nn_fd s2snd) |
||||
|
{ |
||||
|
int rc; |
||||
|
fd_set fds; |
||||
|
int s1rcv_isready = 0; |
||||
|
int s1snd_isready = 0; |
||||
|
int s2rcv_isready = 0; |
||||
|
int s2snd_isready = 0; |
||||
|
|
||||
|
/* Initialise the pollset. */ |
||||
|
FD_ZERO (&fds); |
||||
|
|
||||
|
while (1) { |
||||
|
|
||||
|
/* Wait for network events. Adjust the 'ready' events based
|
||||
|
on the result. */ |
||||
|
if (s1rcv_isready) |
||||
|
FD_CLR (s1rcv, &fds); |
||||
|
else |
||||
|
FD_SET (s1rcv, &fds); |
||||
|
if (s1snd_isready) |
||||
|
FD_CLR (s1snd, &fds); |
||||
|
else |
||||
|
FD_SET (s1snd, &fds); |
||||
|
if (s2rcv_isready) |
||||
|
FD_CLR (s2rcv, &fds); |
||||
|
else |
||||
|
FD_SET (s2rcv, &fds); |
||||
|
if (s2snd_isready) |
||||
|
FD_CLR (s2snd, &fds); |
||||
|
else |
||||
|
FD_SET (s2snd, &fds); |
||||
|
rc = select (0, &fds, NULL, NULL, NULL); |
||||
|
wsa_assert (rc != SOCKET_ERROR); |
||||
|
if (FD_ISSET (s1rcv, &fds)) |
||||
|
s1rcv_isready = 1; |
||||
|
if (FD_ISSET (s1snd, &fds)) |
||||
|
s1snd_isready = 1; |
||||
|
if (FD_ISSET (s2rcv, &fds)) |
||||
|
s2rcv_isready = 1; |
||||
|
if (FD_ISSET (s2snd, &fds)) |
||||
|
s2snd_isready = 1; |
||||
|
|
||||
|
/* If possible, pass the message from s1 to s2. */ |
||||
|
if (s1rcv_isready && s2snd_isready) { |
||||
|
rc = nn_device_mvmsg (device,s1, s2, NN_DONTWAIT); |
||||
|
if (nn_slow (rc < 0)) |
||||
|
return -1; |
||||
|
s1rcv_isready = 0; |
||||
|
s2snd_isready = 0; |
||||
|
} |
||||
|
|
||||
|
/* If possible, pass the message from s2 to s1. */ |
||||
|
if (s2rcv_isready && s1snd_isready) { |
||||
|
rc = nn_device_mvmsg (device,s2, s1, NN_DONTWAIT); |
||||
|
if (nn_slow (rc < 0)) |
||||
|
return -1; |
||||
|
s2rcv_isready = 0; |
||||
|
s1snd_isready = 0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#elif defined NN_HAVE_POLL |
||||
|
|
||||
|
int nn_device_twoway (struct nn_device_recipe *device, |
||||
|
int s1, nn_fd s1rcv, nn_fd s1snd, |
||||
|
int s2, nn_fd s2rcv, nn_fd s2snd) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct pollfd pfd [4]; |
||||
|
|
||||
|
/* Initialise the pollset. */ |
||||
|
pfd [0].fd = s1rcv; |
||||
|
pfd [0].events = POLLIN; |
||||
|
pfd [1].fd = s1snd; |
||||
|
pfd [1].events = POLLIN; |
||||
|
pfd [2].fd = s2rcv; |
||||
|
pfd [2].events = POLLIN; |
||||
|
pfd [3].fd = s2snd; |
||||
|
pfd [3].events = POLLIN; |
||||
|
|
||||
|
while (1) { |
||||
|
|
||||
|
/* Wait for network events. */ |
||||
|
rc = poll (pfd, 4, -1); |
||||
|
errno_assert (rc >= 0); |
||||
|
if (nn_slow (rc < 0 && errno == EINTR)) |
||||
|
return -1; |
||||
|
nn_assert (rc != 0); |
||||
|
|
||||
|
/* Process the events. When the event is received, we cease polling
|
||||
|
for it. */ |
||||
|
if (pfd [0].revents & POLLIN) |
||||
|
pfd [0].events = 0; |
||||
|
if (pfd [1].revents & POLLIN) |
||||
|
pfd [1].events = 0; |
||||
|
if (pfd [2].revents & POLLIN) |
||||
|
pfd [2].events = 0; |
||||
|
if (pfd [3].revents & POLLIN) |
||||
|
pfd [3].events = 0; |
||||
|
|
||||
|
/* If possible, pass the message from s1 to s2. */ |
||||
|
if (pfd [0].events == 0 && pfd [3].events == 0) { |
||||
|
rc = nn_device_mvmsg (device,s1, s2, NN_DONTWAIT); |
||||
|
if (nn_slow (rc < 0)) |
||||
|
return -1; |
||||
|
pfd [0].events = POLLIN; |
||||
|
pfd [3].events = POLLIN; |
||||
|
} |
||||
|
|
||||
|
/* If possible, pass the message from s2 to s1. */ |
||||
|
if (pfd [2].events == 0 && pfd [1].events == 0) { |
||||
|
rc = nn_device_mvmsg (device,s2, s1, NN_DONTWAIT); |
||||
|
if (nn_slow (rc < 0)) |
||||
|
return -1; |
||||
|
pfd [2].events = POLLIN; |
||||
|
pfd [1].events = POLLIN; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#else |
||||
|
#error |
||||
|
#endif |
||||
|
|
||||
|
int nn_device_oneway (struct nn_device_recipe *device, |
||||
|
int s1, NN_UNUSED nn_fd s1rcv, |
||||
|
int s2, NN_UNUSED nn_fd s2snd) |
||||
|
{ |
||||
|
int rc; |
||||
|
|
||||
|
while (1) { |
||||
|
rc = nn_device_mvmsg (device, s1, s2, 0); |
||||
|
if (nn_slow (rc < 0)) |
||||
|
return -1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int nn_device_mvmsg (struct nn_device_recipe *device, |
||||
|
int from, int to, int flags) |
||||
|
{ |
||||
|
int rc; |
||||
|
void *body; |
||||
|
//void *control;
|
||||
|
struct nn_iovec iov; |
||||
|
struct nn_msghdr hdr; |
||||
|
|
||||
|
iov.iov_base = &body; |
||||
|
iov.iov_len = NN_MSG; |
||||
|
memset (&hdr, 0, sizeof (hdr)); |
||||
|
hdr.msg_iov = &iov; |
||||
|
hdr.msg_iovlen = 1; |
||||
|
//hdr.msg_control = &control;
|
||||
|
//hdr.msg_controllen = NN_MSG;
|
||||
|
rc = nn_recvmsg (from, &hdr, flags); |
||||
|
if (nn_slow (rc < 0 && nn_errno () == ETERM)) |
||||
|
return -1; |
||||
|
errno_assert (rc >= 0); |
||||
|
|
||||
|
rc = device->nn_device_rewritemsg (device, from, to, flags, &hdr, rc); |
||||
|
if (nn_slow (rc == -1)) |
||||
|
return -1; |
||||
|
else if (rc == 0) |
||||
|
return 0; |
||||
|
nn_assert(rc == 1); |
||||
|
|
||||
|
rc = nn_sendmsg (to, &hdr, flags); |
||||
|
if (nn_slow (rc < 0 && nn_errno () == ETERM)) |
||||
|
return -1; |
||||
|
errno_assert (rc >= 0); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int nn_device_rewritemsg (struct nn_device_recipe *device, |
||||
|
int from, int to, int flags, struct nn_msghdr *msghdr, int bytes) |
||||
|
{ |
||||
|
return 1; /* always forward */ |
||||
|
} |
||||
|
|
@ -0,0 +1,117 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2014 Drew Crawford. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
//#define NN_HAVE_POLL
|
||||
|
|
||||
|
/* Base class for device. */ |
||||
|
struct nn_device_recipe { |
||||
|
|
||||
|
/* NN_CHECK flags. */ |
||||
|
int required_checks; |
||||
|
|
||||
|
/* The entry function. This checks the inputs according to the
|
||||
|
required_checks flag, chooses the polling function, and starts |
||||
|
the device. You can override this function to implement |
||||
|
additional checks.*/ |
||||
|
int(*nn_device_entry) (struct nn_device_recipe *device, |
||||
|
int s1, int s2, int flags); |
||||
|
|
||||
|
/* The two-way poll function. */ |
||||
|
int (*nn_device_twoway) (struct nn_device_recipe *device, |
||||
|
int s1, nn_fd s1rcv, nn_fd s1snd, int s2, nn_fd s2rcv, nn_fd s2snd); |
||||
|
|
||||
|
/* The one-way poll function. */ |
||||
|
int (*nn_device_oneway) (struct nn_device_recipe *device, |
||||
|
int s1, nn_fd s1rcv, int s2, nn_fd s2snd); |
||||
|
|
||||
|
int (*nn_device_loopback) (struct nn_device_recipe *device, int s); |
||||
|
|
||||
|
/* The movemsg function. */ |
||||
|
int (*nn_device_mvmsg) (struct nn_device_recipe *device, |
||||
|
int from, int to, int flags); |
||||
|
|
||||
|
/* The message intercept function. This function gives you an opportunity
|
||||
|
to modify or cancel an nn_msghdr as it passes from one socket |
||||
|
to the other. |
||||
|
|
||||
|
from - the socket that the msghdr was received from |
||||
|
to - the socket where it is going |
||||
|
flags - the flags that are being used for send and receive functions |
||||
|
msghdr - the nn_msghdr that was received from the from socket |
||||
|
bytes - the actual received length of the msg. |
||||
|
The nn_msghdr->msg_iov->iov_len is not valid because |
||||
|
it contains NN_MSG |
||||
|
|
||||
|
return values: |
||||
|
|
||||
|
1 indicates that the msghdr should be forwarded. |
||||
|
0 indicates that the msghdr should *not* be forwarded, |
||||
|
e.g. the message is dropped in the device |
||||
|
-1 indicates an error. Set errno. |
||||
|
*/ |
||||
|
int (*nn_device_rewritemsg) (struct nn_device_recipe *device, |
||||
|
int from, int to, int flags, struct nn_msghdr *msghdr, int bytes); |
||||
|
}; |
||||
|
|
||||
|
/* Default implementations of the functions. */ |
||||
|
int nn_device_loopback (struct nn_device_recipe *device, int s); |
||||
|
int nn_device_twoway (struct nn_device_recipe *device, |
||||
|
int s1, nn_fd s1rcv, nn_fd s1snd, int s2, nn_fd s2rcv, nn_fd s2snd); |
||||
|
int nn_device_oneway (struct nn_device_recipe *device, |
||||
|
int s1, nn_fd s1rcv, int s2, nn_fd s2snd); |
||||
|
int nn_device_mvmsg (struct nn_device_recipe *device, |
||||
|
int from, int to, int flags); |
||||
|
int nn_device_entry(struct nn_device_recipe *device, |
||||
|
int s1, int s2, int flags); |
||||
|
int nn_device_rewritemsg(struct nn_device_recipe *device, |
||||
|
int from, int to, int flags, struct nn_msghdr *msghdr, int bytes); |
||||
|
|
||||
|
|
||||
|
/* At least one socket must be passed to the device. */ |
||||
|
#define NN_CHECK_AT_LEAST_ONE_SOCKET (1 << 0) |
||||
|
/* Loopback devices are allowed. */ |
||||
|
#define NN_CHECK_ALLOW_LOOPBACK (1 << 1) |
||||
|
/* Bidirectional devices are allowed. */ |
||||
|
#define NN_CHECK_ALLOW_BIDIRECTIONAL (1 << 2) |
||||
|
/* Unidirectional devices are allowed. */ |
||||
|
#define NN_CHECK_ALLOW_UNIDIRECTIONAL (1<<3) |
||||
|
/* Both sockets must be raw. */ |
||||
|
#define NN_CHECK_REQUIRE_RAW_SOCKETS (1 << 4) |
||||
|
/* Both sockets must be same protocol family. */ |
||||
|
#define NN_CHECK_SAME_PROTOCOL_FAMILY (1 << 5) |
||||
|
/* Check socket directionality. */ |
||||
|
#define NN_CHECK_SOCKET_DIRECTIONALITY (1 << 6) |
||||
|
|
||||
|
/* Allows spawning a custom device from a recipe */ |
||||
|
int nn_custom_device(struct nn_device_recipe *device, |
||||
|
int s1, int s2, int flags); |
||||
|
|
||||
|
static struct nn_device_recipe nn_ordinary_device = { |
||||
|
NN_CHECK_AT_LEAST_ONE_SOCKET | NN_CHECK_ALLOW_LOOPBACK | NN_CHECK_ALLOW_BIDIRECTIONAL | NN_CHECK_REQUIRE_RAW_SOCKETS | NN_CHECK_SAME_PROTOCOL_FAMILY | NN_CHECK_SOCKET_DIRECTIONALITY | NN_CHECK_ALLOW_UNIDIRECTIONAL, |
||||
|
nn_device_entry, |
||||
|
nn_device_twoway, |
||||
|
nn_device_oneway, |
||||
|
nn_device_loopback, |
||||
|
nn_device_mvmsg, |
||||
|
nn_device_rewritemsg |
||||
|
}; |
||||
|
|
@ -0,0 +1,381 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2014 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#include "../nn.h" |
||||
|
|
||||
|
#if defined NN_HAVE_WINDOWS |
||||
|
|
||||
|
#include "../utils/err.h" |
||||
|
|
||||
|
int nn_tcpmuxd (int port) |
||||
|
{ |
||||
|
errno = EPROTONOSUPPORT; |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
#else |
||||
|
|
||||
|
#include "../utils/thread.h" |
||||
|
#include "../utils/attr.h" |
||||
|
#include "../utils/err.h" |
||||
|
#include "../utils/int.h" |
||||
|
#include "../utils/cont.h" |
||||
|
#include "../utils/wire.h" |
||||
|
#include "../utils/alloc.h" |
||||
|
#include "../utils/list.h" |
||||
|
#include "../utils/mutex.h" |
||||
|
#include "../utils/closefd.h" |
||||
|
|
||||
|
#include <stddef.h> |
||||
|
#include <string.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <unistd.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <netinet/tcp.h> |
||||
|
#include <sys/time.h> |
||||
|
#ifndef __PNACL |
||||
|
#include <sys/un.h> |
||||
|
#else |
||||
|
#include <glibc-compat/sys/un.h> |
||||
|
#include <glibc-compat/sys/uio.h> |
||||
|
#endif |
||||
|
#include <stddef.h> |
||||
|
#include <ctype.h> |
||||
|
#include <poll.h> |
||||
|
|
||||
|
struct nn_tcpmuxd_ctx { |
||||
|
int tcp_listener; |
||||
|
int ipc_listener; |
||||
|
struct nn_list conns; |
||||
|
struct pollfd *pfd; |
||||
|
size_t pfd_size; |
||||
|
size_t pfd_capacity; |
||||
|
struct nn_thread thread; |
||||
|
}; |
||||
|
|
||||
|
struct nn_tcpmuxd_conn { |
||||
|
int fd; |
||||
|
char *service; |
||||
|
struct nn_list_item item; |
||||
|
}; |
||||
|
|
||||
|
/* Forward declarations. */ |
||||
|
static void nn_tcpmuxd_routine (void *arg); |
||||
|
static void nn_tcpmuxd_disconnect (struct nn_tcpmuxd_ctx *ctx, int i); |
||||
|
static int nn_tcpmuxd_send_fd (int s, int fd); |
||||
|
|
||||
|
int nn_tcpmuxd (int port) |
||||
|
{ |
||||
|
int rc; |
||||
|
int tcp_listener; |
||||
|
int ipc_listener; |
||||
|
int opt; |
||||
|
struct sockaddr_in tcp_addr; |
||||
|
struct sockaddr_un ipc_addr; |
||||
|
struct nn_tcpmuxd_ctx *ctx; |
||||
|
|
||||
|
/* Start listening on the specified TCP port. */ |
||||
|
errno = 0; |
||||
|
tcp_listener = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); |
||||
|
if (tcp_listener < 0) { return -1; } |
||||
|
opt = 1; |
||||
|
rc = setsockopt (tcp_listener, SOL_SOCKET, SO_REUSEADDR, &opt, |
||||
|
sizeof (opt)); |
||||
|
if (rc != 0) { return -1; } |
||||
|
memset (&tcp_addr, 0, sizeof (tcp_addr)); |
||||
|
tcp_addr.sin_family = AF_INET; |
||||
|
tcp_addr.sin_port = htons (port); |
||||
|
tcp_addr.sin_addr.s_addr = INADDR_ANY; |
||||
|
rc = bind (tcp_listener, (struct sockaddr*) &tcp_addr, sizeof (tcp_addr)); |
||||
|
if (rc != 0) { return -1; } |
||||
|
rc = listen (tcp_listener, 100); |
||||
|
if (rc != 0) { return -1; } |
||||
|
|
||||
|
/* Start listening for incoming IPC connections. */ |
||||
|
ipc_addr.sun_family = AF_UNIX; |
||||
|
snprintf (ipc_addr.sun_path, sizeof (ipc_addr.sun_path), |
||||
|
"/tmp/tcpmux-%d.ipc", (int) port); |
||||
|
unlink (ipc_addr.sun_path); |
||||
|
errno = 0; |
||||
|
ipc_listener = socket (AF_UNIX, SOCK_STREAM, 0); |
||||
|
if (ipc_listener < 0) { |
||||
|
return -1; |
||||
|
} |
||||
|
rc = bind (ipc_listener, (struct sockaddr*) &ipc_addr, sizeof (ipc_addr)); |
||||
|
if (rc != 0) { return -1; } |
||||
|
rc = listen (ipc_listener, 100); |
||||
|
if (rc != 0) { return -1; } |
||||
|
|
||||
|
/* Allocate a context for the daemon. */ |
||||
|
ctx = nn_alloc (sizeof (struct nn_tcpmuxd_ctx), "tcpmuxd context"); |
||||
|
alloc_assert (ctx); |
||||
|
ctx->tcp_listener = tcp_listener; |
||||
|
ctx->ipc_listener = ipc_listener; |
||||
|
nn_list_init (&ctx->conns); |
||||
|
ctx->pfd = nn_alloc (sizeof (struct pollfd) * 16, "tcpmuxd pollfd"); |
||||
|
alloc_assert (ctx->pfd); |
||||
|
ctx->pfd_capacity = 16; |
||||
|
ctx->pfd [0].fd = tcp_listener; |
||||
|
ctx->pfd [0].events = POLLIN; |
||||
|
ctx->pfd [1].fd = ipc_listener; |
||||
|
ctx->pfd [1].events = POLLIN; |
||||
|
ctx->pfd_size = 2; |
||||
|
|
||||
|
/* Run the daemon in a dedicated thread. */ |
||||
|
nn_thread_init (&ctx->thread, nn_tcpmuxd_routine, ctx); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
/* Main body of the daemon. */ |
||||
|
static void nn_tcpmuxd_routine (void *arg) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct nn_tcpmuxd_ctx *ctx; |
||||
|
int conn; |
||||
|
int pos; |
||||
|
char service [256]; |
||||
|
struct nn_tcpmuxd_conn *tc = 0; |
||||
|
size_t sz; |
||||
|
ssize_t ssz; |
||||
|
int i; |
||||
|
struct nn_list_item *it; |
||||
|
unsigned char buf [2]; |
||||
|
struct timeval tv; |
||||
|
|
||||
|
ctx = (struct nn_tcpmuxd_ctx*) arg; |
||||
|
|
||||
|
while (1) { |
||||
|
|
||||
|
/* Wait for events. */ |
||||
|
rc = (int32_t)poll (ctx->pfd, (int32_t)ctx->pfd_size, -1); |
||||
|
errno_assert (rc >= 0); |
||||
|
nn_assert (rc != 0); |
||||
|
|
||||
|
/* There's an incoming TCP connection. */ |
||||
|
if (ctx->pfd [0].revents & POLLIN) { |
||||
|
|
||||
|
/* Accept the connection. */ |
||||
|
conn = accept (ctx->tcp_listener, NULL, NULL); |
||||
|
if (conn < 0 && errno == ECONNABORTED) |
||||
|
continue; |
||||
|
errno_assert (conn >= 0); |
||||
|
|
||||
|
/* Set timeouts to prevent malevolent client blocking the service.
|
||||
|
Note that these options are not supported on Solaris. */ |
||||
|
tv.tv_sec = 0; |
||||
|
tv.tv_usec = 100000; |
||||
|
rc = setsockopt (conn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (tv)); |
||||
|
errno_assert (rc == 0 || (rc < 0 && errno == ENOPROTOOPT)); |
||||
|
rc = setsockopt (conn, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof (tv)); |
||||
|
errno_assert (rc == 0 || (rc < 0 && errno == ENOPROTOOPT)); |
||||
|
|
||||
|
/* Read TCPMUX header. */ |
||||
|
pos = 0; |
||||
|
while (1) { |
||||
|
nn_assert (pos < sizeof (service)); |
||||
|
ssz = recv (conn, &service [pos], 1, 0); |
||||
|
if (ssz < 0 && errno == EAGAIN) { |
||||
|
close (conn); |
||||
|
continue; |
||||
|
} |
||||
|
errno_assert (ssz >= 0); |
||||
|
nn_assert (ssz == 1); |
||||
|
service [pos] = tolower ((uint32_t)service [pos]); |
||||
|
if (pos > 0 && service [pos - 1] == 0x0d && |
||||
|
service [pos] == 0x0a) |
||||
|
break; |
||||
|
++pos; |
||||
|
} |
||||
|
service [pos - 1] = 0; |
||||
|
|
||||
|
/* Check whether specified service is listening. */ |
||||
|
for (it = nn_list_begin (&ctx->conns); |
||||
|
it != nn_list_end (&ctx->conns); |
||||
|
it = nn_list_next (&ctx->conns, it)) { |
||||
|
tc = nn_cont (it, struct nn_tcpmuxd_conn, item); |
||||
|
if (strcmp (service, tc->service) == 0) |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
/* If no one is listening, tear down the connection. */ |
||||
|
if (it == nn_list_end (&ctx->conns)) { |
||||
|
ssz = send (conn, "-\x0d\x0a", 3, 0); |
||||
|
if (ssz < 0 && errno == EAGAIN) { |
||||
|
close (conn); |
||||
|
continue; |
||||
|
} |
||||
|
errno_assert (ssz >= 0); |
||||
|
nn_assert (ssz == 3); |
||||
|
close (conn); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
/* Send TCPMUX reply. */ |
||||
|
ssz = send (conn, "+\x0d\x0a", 3, 0); |
||||
|
if (ssz < 0 && errno == EAGAIN) { |
||||
|
close (conn); |
||||
|
continue; |
||||
|
} |
||||
|
errno_assert (ssz >= 0); |
||||
|
nn_assert (ssz == 3); |
||||
|
nn_assert (tc != 0); |
||||
|
|
||||
|
/* Pass the file descriptor to the listening process. */ |
||||
|
rc = nn_tcpmuxd_send_fd (tc->fd, conn); |
||||
|
errno_assert (rc == 0); |
||||
|
} |
||||
|
|
||||
|
/* There's an incoming IPC connection. */ |
||||
|
if (ctx->pfd [1].revents & POLLIN) { |
||||
|
|
||||
|
/* Accept the connection. */ |
||||
|
conn = accept (ctx->ipc_listener, NULL, NULL); |
||||
|
if (conn < 0 && errno == ECONNABORTED) |
||||
|
continue; |
||||
|
errno_assert (conn >= 0); |
||||
|
|
||||
|
/* Create new connection entry. */ |
||||
|
tc = nn_alloc (sizeof (struct nn_tcpmuxd_conn), "tcpmuxd_conn"); |
||||
|
nn_assert (tc); |
||||
|
tc->fd = conn; |
||||
|
nn_list_item_init (&tc->item); |
||||
|
|
||||
|
/* Adjust the pollset. We will poll for errors only. */ |
||||
|
ctx->pfd_size++; |
||||
|
if (ctx->pfd_size > ctx->pfd_capacity) { |
||||
|
ctx->pfd_capacity *= 2; |
||||
|
ctx->pfd = nn_realloc (ctx->pfd, |
||||
|
sizeof (struct pollfd) * ctx->pfd_capacity); |
||||
|
alloc_assert (ctx->pfd); |
||||
|
} |
||||
|
ctx->pfd [ctx->pfd_size - 1].fd = conn; |
||||
|
ctx->pfd [ctx->pfd_size - 1].events = 0; |
||||
|
ctx->pfd [ctx->pfd_size - 1].revents = 0; |
||||
|
|
||||
|
/* Read the connection header. */ |
||||
|
ssz = recv (conn, buf, 2, 0); |
||||
|
errno_assert (ssz >= 0); |
||||
|
nn_assert (ssz == 2); |
||||
|
sz = nn_gets (buf); |
||||
|
tc->service = nn_alloc (sz + 1, "tcpmuxd_conn.service"); |
||||
|
nn_assert (tc->service); |
||||
|
ssz = recv (conn, tc->service, sz, 0); |
||||
|
errno_assert (ssz >= 0); |
||||
|
nn_assert (ssz == sz); |
||||
|
for (i = 0; i != sz; ++i) |
||||
|
tc->service [i] = tolower ((uint32_t)tc->service [i]); |
||||
|
tc->service [sz] = 0; |
||||
|
|
||||
|
/* Add the entry to the IPC connections list. */ |
||||
|
nn_list_insert (&ctx->conns, &tc->item, nn_list_end (&ctx->conns)); |
||||
|
} |
||||
|
|
||||
|
for (i = 2; i < ctx->pfd_size; ++i) { |
||||
|
if (ctx->pfd [i].revents & POLLERR || |
||||
|
ctx->pfd [i].revents & POLLHUP) { |
||||
|
nn_tcpmuxd_disconnect (ctx, i); |
||||
|
i--; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Tear down the IPC connection with index i in the pollset. */ |
||||
|
static void nn_tcpmuxd_disconnect (struct nn_tcpmuxd_ctx *ctx, int i) |
||||
|
{ |
||||
|
int fd; |
||||
|
struct nn_list_item *it; |
||||
|
struct nn_tcpmuxd_conn *conn; |
||||
|
|
||||
|
fd = ctx->pfd [i].fd; |
||||
|
|
||||
|
/* Remove the descriptor from the pollset. */ |
||||
|
if (ctx->pfd_size > 3) |
||||
|
ctx->pfd [i] = ctx->pfd [ctx->pfd_size - 1]; |
||||
|
ctx->pfd_size--; |
||||
|
|
||||
|
/* Remove the connection entry. */ |
||||
|
for (it = nn_list_begin (&ctx->conns); |
||||
|
it != nn_list_end (&ctx->conns); |
||||
|
it = nn_list_next (&ctx->conns, it)) { |
||||
|
conn = nn_cont (it, struct nn_tcpmuxd_conn, item); |
||||
|
if (conn->fd == fd) { |
||||
|
nn_list_erase (&ctx->conns, it); |
||||
|
nn_free (conn->service); |
||||
|
nn_free (conn); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Send file descriptor fd to IPC socket s. */ |
||||
|
static int nn_tcpmuxd_send_fd (int s, int fd) |
||||
|
{ |
||||
|
int rc; |
||||
|
struct iovec iov; |
||||
|
char c = 0; |
||||
|
struct msghdr msg; |
||||
|
char control [sizeof (struct cmsghdr) + 10]; |
||||
|
#if defined NN_HAVE_MSG_CONTROL |
||||
|
struct cmsghdr *cmsg; |
||||
|
#endif |
||||
|
|
||||
|
/* Compose the message. We'll send one byte long dummy message
|
||||
|
accompanied with the fd.*/ |
||||
|
iov.iov_base = &c; |
||||
|
iov.iov_len = 1; |
||||
|
memset (&msg, 0, sizeof (msg)); |
||||
|
msg.msg_iov = &iov; |
||||
|
msg.msg_iovlen = 1; |
||||
|
|
||||
|
/* Attach the file descriptor to the message. */ |
||||
|
#if defined NN_HAVE_MSG_CONTROL |
||||
|
msg.msg_control = control; |
||||
|
msg.msg_controllen = sizeof (control); |
||||
|
cmsg = CMSG_FIRSTHDR (&msg); |
||||
|
cmsg->cmsg_level = SOL_SOCKET; |
||||
|
cmsg->cmsg_type = SCM_RIGHTS; |
||||
|
cmsg->cmsg_len = CMSG_LEN (sizeof (fd)); |
||||
|
int *data = (int*) CMSG_DATA (cmsg); |
||||
|
*data = fd; |
||||
|
msg.msg_controllen = cmsg->cmsg_len; |
||||
|
#else |
||||
|
msg.msg_accrights = (caddr_t) &fd; |
||||
|
msg.msg_accrightslen = sizeof (fd); |
||||
|
#endif |
||||
|
|
||||
|
/* Pass the file descriptor to the registered process. */ |
||||
|
rc = (int32_t)sendmsg (s, &msg, 0); |
||||
|
if (rc < 0) |
||||
|
return -1; |
||||
|
nn_assert (rc == 1); |
||||
|
|
||||
|
/* Sending the file descriptor to other process acts as dup().
|
||||
|
Therefore, we have to close the local copy of the file descriptor. */ |
||||
|
nn_closefd (fd); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
#endif |
@ -0,0 +1,37 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef INPROC_H_INCLUDED |
||||
|
#define INPROC_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_INPROC -1 |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,37 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef IPC_H_INCLUDED |
||||
|
#define IPC_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_IPC -2 |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,395 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2014 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_H_INCLUDED |
||||
|
#define NN_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#include <errno.h> |
||||
|
#include <stddef.h> |
||||
|
#include "nn_config.h" |
||||
|
|
||||
|
/* Handle DSO symbol visibility */ |
||||
|
#if defined NN_NO_EXPORTS |
||||
|
# define NN_EXPORT |
||||
|
#else |
||||
|
# if defined _WIN32 |
||||
|
# if defined NN_EXPORTS |
||||
|
# define NN_EXPORT __declspec(dllexport) |
||||
|
# else |
||||
|
# define NN_EXPORT __declspec(dllimport) |
||||
|
# endif |
||||
|
# else |
||||
|
# if defined __SUNPRO_C |
||||
|
# define NN_EXPORT __global |
||||
|
# elif (defined __GNUC__ && __GNUC__ >= 4) || \ |
||||
|
defined __INTEL_COMPILER || defined __clang__ |
||||
|
# define NN_EXPORT __attribute__ ((visibility("default"))) |
||||
|
# else |
||||
|
# define NN_EXPORT |
||||
|
# endif |
||||
|
# endif |
||||
|
#endif |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* ABI versioning support. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* Don't change this unless you know exactly what you're doing and have */ |
||||
|
/* read and understand the following documents: */ |
||||
|
/* www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html */ |
||||
|
/* www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html */ |
||||
|
|
||||
|
/* The current interface version. */ |
||||
|
#define NN_VERSION_CURRENT 2 |
||||
|
|
||||
|
/* The latest revision of the current interface. */ |
||||
|
#define NN_VERSION_REVISION 2 |
||||
|
|
||||
|
/* How many past interface versions are still supported. */ |
||||
|
#define NN_VERSION_AGE 2 |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Errors. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* A number random enough not to collide with different errno ranges on */ |
||||
|
/* different OSes. The assumption is that error_t is at least 32-bit type. */ |
||||
|
#define NN_HAUSNUMERO 156384712 |
||||
|
|
||||
|
/* On some platforms some standard POSIX errnos are not defined. */ |
||||
|
#ifndef ENOTSUP |
||||
|
#define ENOTSUP (NN_HAUSNUMERO + 1) |
||||
|
#endif |
||||
|
#ifndef EPROTONOSUPPORT |
||||
|
#define EPROTONOSUPPORT (NN_HAUSNUMERO + 2) |
||||
|
#endif |
||||
|
#ifndef ENOBUFS |
||||
|
#define ENOBUFS (NN_HAUSNUMERO + 3) |
||||
|
#endif |
||||
|
#ifndef ENETDOWN |
||||
|
#define ENETDOWN (NN_HAUSNUMERO + 4) |
||||
|
#endif |
||||
|
#ifndef EADDRINUSE |
||||
|
#define EADDRINUSE (NN_HAUSNUMERO + 5) |
||||
|
#endif |
||||
|
#ifndef EADDRNOTAVAIL |
||||
|
#define EADDRNOTAVAIL (NN_HAUSNUMERO + 6) |
||||
|
#endif |
||||
|
#ifndef ECONNREFUSED |
||||
|
#define ECONNREFUSED (NN_HAUSNUMERO + 7) |
||||
|
#endif |
||||
|
#ifndef EINPROGRESS |
||||
|
#define EINPROGRESS (NN_HAUSNUMERO + 8) |
||||
|
#endif |
||||
|
#ifndef ENOTSOCK |
||||
|
#define ENOTSOCK (NN_HAUSNUMERO + 9) |
||||
|
#endif |
||||
|
#ifndef EAFNOSUPPORT |
||||
|
#define EAFNOSUPPORT (NN_HAUSNUMERO + 10) |
||||
|
#endif |
||||
|
#ifndef EPROTO |
||||
|
#define EPROTO (NN_HAUSNUMERO + 11) |
||||
|
#endif |
||||
|
#ifndef EAGAIN |
||||
|
#define EAGAIN (NN_HAUSNUMERO + 12) |
||||
|
#endif |
||||
|
#ifndef EBADF |
||||
|
#define EBADF (NN_HAUSNUMERO + 13) |
||||
|
#endif |
||||
|
#ifndef EINVAL |
||||
|
#define EINVAL (NN_HAUSNUMERO + 14) |
||||
|
#endif |
||||
|
#ifndef EMFILE |
||||
|
#define EMFILE (NN_HAUSNUMERO + 15) |
||||
|
#endif |
||||
|
#ifndef EFAULT |
||||
|
#define EFAULT (NN_HAUSNUMERO + 16) |
||||
|
#endif |
||||
|
#ifndef EACCES |
||||
|
#define EACCES (NN_HAUSNUMERO + 17) |
||||
|
#endif |
||||
|
#ifndef EACCESS |
||||
|
#define EACCESS (EACCES) |
||||
|
#endif |
||||
|
#ifndef ENETRESET |
||||
|
#define ENETRESET (NN_HAUSNUMERO + 18) |
||||
|
#endif |
||||
|
#ifndef ENETUNREACH |
||||
|
#define ENETUNREACH (NN_HAUSNUMERO + 19) |
||||
|
#endif |
||||
|
#ifndef EHOSTUNREACH |
||||
|
#define EHOSTUNREACH (NN_HAUSNUMERO + 20) |
||||
|
#endif |
||||
|
#ifndef ENOTCONN |
||||
|
#define ENOTCONN (NN_HAUSNUMERO + 21) |
||||
|
#endif |
||||
|
#ifndef EMSGSIZE |
||||
|
#define EMSGSIZE (NN_HAUSNUMERO + 22) |
||||
|
#endif |
||||
|
#ifndef ETIMEDOUT |
||||
|
#define ETIMEDOUT (NN_HAUSNUMERO + 23) |
||||
|
#endif |
||||
|
#ifndef ECONNABORTED |
||||
|
#define ECONNABORTED (NN_HAUSNUMERO + 24) |
||||
|
#endif |
||||
|
#ifndef ECONNRESET |
||||
|
#define ECONNRESET (NN_HAUSNUMERO + 25) |
||||
|
#endif |
||||
|
#ifndef ENOPROTOOPT |
||||
|
#define ENOPROTOOPT (NN_HAUSNUMERO + 26) |
||||
|
#endif |
||||
|
#ifndef EISCONN |
||||
|
#define EISCONN (NN_HAUSNUMERO + 27) |
||||
|
#define NN_EISCONN_DEFINED |
||||
|
#endif |
||||
|
#ifndef ESOCKTNOSUPPORT |
||||
|
#define ESOCKTNOSUPPORT (NN_HAUSNUMERO + 28) |
||||
|
#endif |
||||
|
|
||||
|
/* Native nanomsg error codes. */ |
||||
|
#ifndef ETERM |
||||
|
#define ETERM (NN_HAUSNUMERO + 53) |
||||
|
#endif |
||||
|
#ifndef EFSM |
||||
|
#define EFSM (NN_HAUSNUMERO + 54) |
||||
|
#endif |
||||
|
|
||||
|
/* This function retrieves the errno as it is known to the library. */ |
||||
|
/* The goal of this function is to make the code 100% portable, including */ |
||||
|
/* where the library is compiled with certain CRT library (on Windows) and */ |
||||
|
/* linked to an application that uses different CRT library. */ |
||||
|
NN_EXPORT int nn_errno (void); |
||||
|
|
||||
|
/* Resolves system errors and native errors to human-readable string. */ |
||||
|
NN_EXPORT const char *nn_strerror (int errnum); |
||||
|
|
||||
|
|
||||
|
/* Returns the symbol name (e.g. "NN_REQ") and value at a specified index. */ |
||||
|
/* If the index is out-of-range, returns NULL and sets errno to EINVAL */ |
||||
|
/* General usage is to start at i=0 and iterate until NULL is returned. */ |
||||
|
NN_EXPORT const char *nn_symbol (int i, int *value); |
||||
|
|
||||
|
/* Constants that are returned in `ns` member of nn_symbol_properties */ |
||||
|
#define NN_NS_NAMESPACE 0 |
||||
|
#define NN_NS_VERSION 1 |
||||
|
#define NN_NS_DOMAIN 2 |
||||
|
#define NN_NS_TRANSPORT 3 |
||||
|
#define NN_NS_PROTOCOL 4 |
||||
|
#define NN_NS_OPTION_LEVEL 5 |
||||
|
#define NN_NS_SOCKET_OPTION 6 |
||||
|
#define NN_NS_TRANSPORT_OPTION 7 |
||||
|
#define NN_NS_OPTION_TYPE 8 |
||||
|
#define NN_NS_OPTION_UNIT 9 |
||||
|
#define NN_NS_FLAG 10 |
||||
|
#define NN_NS_ERROR 11 |
||||
|
#define NN_NS_LIMIT 12 |
||||
|
#define NN_NS_EVENT 13 |
||||
|
|
||||
|
/* Constants that are returned in `type` member of nn_symbol_properties */ |
||||
|
#define NN_TYPE_NONE 0 |
||||
|
#define NN_TYPE_INT 1 |
||||
|
#define NN_TYPE_STR 2 |
||||
|
|
||||
|
/* Constants that are returned in the `unit` member of nn_symbol_properties */ |
||||
|
#define NN_UNIT_NONE 0 |
||||
|
#define NN_UNIT_BYTES 1 |
||||
|
#define NN_UNIT_MILLISECONDS 2 |
||||
|
#define NN_UNIT_PRIORITY 3 |
||||
|
#define NN_UNIT_BOOLEAN 4 |
||||
|
|
||||
|
/* Structure that is returned from nn_symbol */ |
||||
|
struct nn_symbol_properties { |
||||
|
|
||||
|
/* The constant value */ |
||||
|
int value; |
||||
|
|
||||
|
/* The constant name */ |
||||
|
const char* name; |
||||
|
|
||||
|
/* The constant namespace, or zero for namespaces themselves */ |
||||
|
int ns; |
||||
|
|
||||
|
/* The option type for socket option constants */ |
||||
|
int type; |
||||
|
|
||||
|
/* The unit for the option value for socket option constants */ |
||||
|
int unit; |
||||
|
}; |
||||
|
|
||||
|
/* Fills in nn_symbol_properties structure and returns it's length */ |
||||
|
/* If the index is out-of-range, returns 0 */ |
||||
|
/* General usage is to start at i=0 and iterate until zero is returned. */ |
||||
|
NN_EXPORT int nn_symbol_info (int i, |
||||
|
struct nn_symbol_properties *buf, int buflen); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Helper function for shutting down multi-threaded applications. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
NN_EXPORT void nn_term (void); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Zero-copy support. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
#define NN_MSG ((size_t) -1) |
||||
|
|
||||
|
NN_EXPORT void *nn_allocmsg (size_t size, int type); |
||||
|
NN_EXPORT void *nn_reallocmsg (void *msg, size_t size); |
||||
|
NN_EXPORT int nn_freemsg (void *msg); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Socket definition. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
struct nn_iovec { |
||||
|
void *iov_base; |
||||
|
size_t iov_len; |
||||
|
}; |
||||
|
|
||||
|
struct nn_msghdr { |
||||
|
struct nn_iovec *msg_iov; |
||||
|
int msg_iovlen; |
||||
|
void *msg_control; |
||||
|
size_t msg_controllen; |
||||
|
}; |
||||
|
|
||||
|
struct nn_cmsghdr { |
||||
|
size_t cmsg_len; |
||||
|
int cmsg_level; |
||||
|
int cmsg_type; |
||||
|
}; |
||||
|
|
||||
|
/* Internal stuff. Not to be used directly. */ |
||||
|
NN_EXPORT struct nn_cmsghdr *nn_cmsg_nxthdr_ ( |
||||
|
const struct nn_msghdr *mhdr, |
||||
|
const struct nn_cmsghdr *cmsg); |
||||
|
#define NN_CMSG_ALIGN_(len) \ |
||||
|
(((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) |
||||
|
|
||||
|
/* POSIX-defined msghdr manipulation. */ |
||||
|
|
||||
|
#define NN_CMSG_FIRSTHDR(mhdr) \ |
||||
|
nn_cmsg_nxthdr_ ((struct nn_msghdr*) (mhdr), NULL) |
||||
|
|
||||
|
#define NN_CMSG_NXTHDR(mhdr, cmsg) \ |
||||
|
nn_cmsg_nxthdr_ ((struct nn_msghdr*) (mhdr), (struct nn_cmsghdr*) (cmsg)) |
||||
|
|
||||
|
#define NN_CMSG_DATA(cmsg) \ |
||||
|
((unsigned char*) (((struct nn_cmsghdr*) (cmsg)) + 1)) |
||||
|
|
||||
|
/* Extensions to POSIX defined by RFC 3542. */ |
||||
|
|
||||
|
#define NN_CMSG_SPACE(len) \ |
||||
|
(NN_CMSG_ALIGN_ (len) + NN_CMSG_ALIGN_ (sizeof (struct nn_cmsghdr))) |
||||
|
|
||||
|
#define NN_CMSG_LEN(len) \ |
||||
|
(NN_CMSG_ALIGN_ (sizeof (struct nn_cmsghdr)) + (len)) |
||||
|
|
||||
|
/* SP address families. */ |
||||
|
#define AF_SP 1 |
||||
|
#define AF_SP_RAW 2 |
||||
|
|
||||
|
/* Max size of an SP address. */ |
||||
|
#define NN_SOCKADDR_MAX 128 |
||||
|
|
||||
|
/* Socket option levels: Negative numbers are reserved for transports,
|
||||
|
positive for socket types. */ |
||||
|
#define NN_SOL_SOCKET 0 |
||||
|
|
||||
|
/* Generic socket options (NN_SOL_SOCKET level). */ |
||||
|
#define NN_LINGER 1 |
||||
|
#define NN_SNDBUF 2 |
||||
|
#define NN_RCVBUF 3 |
||||
|
#define NN_SNDTIMEO 4 |
||||
|
#define NN_RCVTIMEO 5 |
||||
|
#define NN_RECONNECT_IVL 6 |
||||
|
#define NN_RECONNECT_IVL_MAX 7 |
||||
|
#define NN_SNDPRIO 8 |
||||
|
#define NN_RCVPRIO 9 |
||||
|
#define NN_SNDFD 10 |
||||
|
#define NN_RCVFD 11 |
||||
|
#define NN_DOMAIN 12 |
||||
|
#define NN_PROTOCOL 13 |
||||
|
#define NN_IPV4ONLY 14 |
||||
|
#define NN_SOCKET_NAME 15 |
||||
|
#define NN_RCVMAXSIZE 16 |
||||
|
|
||||
|
/* Send/recv options. */ |
||||
|
#define NN_DONTWAIT 1 |
||||
|
|
||||
|
/* Ancillary data. */ |
||||
|
#define PROTO_SP 1 |
||||
|
#define SP_HDR 1 |
||||
|
|
||||
|
NN_EXPORT int nn_socket (int domain, int protocol); |
||||
|
NN_EXPORT int nn_close (int s); |
||||
|
NN_EXPORT int nn_setsockopt (int s, int level, int option, const void *optval, |
||||
|
size_t optvallen); |
||||
|
NN_EXPORT int nn_getsockopt (int s, int level, int option, void *optval, |
||||
|
size_t *optvallen); |
||||
|
NN_EXPORT int nn_bind (int s, const char *addr); |
||||
|
NN_EXPORT int nn_connect (int s, const char *addr); |
||||
|
NN_EXPORT int nn_shutdown (int s, int how); |
||||
|
NN_EXPORT int nn_send (int s, const void *buf, size_t len, int flags); |
||||
|
NN_EXPORT int nn_recv (int s, void *buf, size_t len, int flags); |
||||
|
NN_EXPORT int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags); |
||||
|
NN_EXPORT int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Socket mutliplexing support. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
#define NN_POLLIN 1 |
||||
|
#define NN_POLLOUT 2 |
||||
|
|
||||
|
struct nn_pollfd { |
||||
|
int fd; |
||||
|
short events; |
||||
|
short revents; |
||||
|
}; |
||||
|
|
||||
|
NN_EXPORT int nn_poll (struct nn_pollfd *fds, int nfds, int timeout); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Built-in support for devices. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
NN_EXPORT int nn_device (int s1, int s2); |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Built-in support for multiplexers. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
NN_EXPORT int nn_tcpmuxd (int port); |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,75 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NNCONFIG_H_INCLUDED |
||||
|
#define NNCONFIG_H_INCLUDED |
||||
|
|
||||
|
#ifdef __APPLE__ |
||||
|
#define NN_HAVE_OSX 1 |
||||
|
#endif |
||||
|
|
||||
|
#define NN_HAVE_POLL 1 // must have
|
||||
|
#define NN_HAVE_SEMAPHORE 1 // must have
|
||||
|
|
||||
|
// need one of following 3, listed in order of precedence, used by efd*
|
||||
|
//#define NN_HAVE_EVENTFD 1
|
||||
|
//#define NN_HAVE_PIPE 1
|
||||
|
#define NN_HAVE_SOCKETPAIR 1 |
||||
|
|
||||
|
// need one of following 3, listed in order of precedence, used by poller*
|
||||
|
#define NN_USE_POLL 1 |
||||
|
//#define NN_USE_EPOLL 1
|
||||
|
//#define NN_USE_KQUEUE 1
|
||||
|
|
||||
|
#define NN_DISABLE_GETADDRINFO_A 1 |
||||
|
#define NN_USE_LITERAL_IFADDR 1 |
||||
|
#define NN_HAVE_STDINT 1 |
||||
|
|
||||
|
#define NN_HAVE_MSG_CONTROL 1 |
||||
|
//#define STANDALONE 1
|
||||
|
|
||||
|
#ifdef __PNACL |
||||
|
//#define FD_CLOEXEC 1
|
||||
|
|
||||
|
void PostMessage(const char* format, ...); |
||||
|
#include <glibc-compat/sys/uio.h> |
||||
|
#include <glibc-compat/sys/un.h> |
||||
|
#else |
||||
|
//#define NN_ENABLE_EXTRA 1
|
||||
|
#define PostMessage printf |
||||
|
#include <sys/uio.h> |
||||
|
#include <sys/un.h> |
||||
|
#endif |
||||
|
|
||||
|
/* Size of the buffer used for batch-reads of inbound data. To keep the
|
||||
|
performance optimal make sure that this value is larger than network MTU. */ |
||||
|
#define NN_USOCK_BATCH_SIZE (2048) |
||||
|
//#define NN_USOCK_BATCH_SIZE (_NN_USOCK_BATCH_SIZE - 5 - 256 - 16) // adjust for veclen/clen + sizeof(ctrl)
|
||||
|
|
||||
|
#if defined __PNACL || defined __APPLE__ |
||||
|
#define NN_USE_MYMSG 1 |
||||
|
#endif |
||||
|
|
||||
|
#define nn_errstr() nn_strerror(nn_errno()) |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,39 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef PAIR_H_INCLUDED |
||||
|
#define PAIR_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_PROTO_PAIR 1 |
||||
|
|
||||
|
#define NN_PAIR (NN_PROTO_PAIR * 16 + 0) |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,41 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012 Martin Sustrik All rights reserved. |
||||
|
Copyright (c) 2013 GoPivotal, Inc. All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef PIPELINE_H_INCLUDED |
||||
|
#define PIPELINE_H_INCLUDED |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
|
||||
|
#define NN_PROTO_PIPELINE 5 |
||||
|
|
||||
|
#define NN_PUSH (NN_PROTO_PIPELINE * 16 + 0) |
||||
|
#define NN_PULL (NN_PROTO_PIPELINE * 16 + 1) |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,12 @@ |
|||||
|
prefix=@CMAKE_INSTALL_PREFIX@ |
||||
|
exec_prefix=${prefix} |
||||
|
includedir=${prefix}/include |
||||
|
libdir=${prefix}/lib |
||||
|
|
||||
|
Name: @CMAKE_PROJECT_NAME@ |
||||
|
Description: @NN_DESCRIPTION@ |
||||
|
URL: http://nanomsg.org/ |
||||
|
Version: @NN_VERSION_STR@ |
||||
|
Requires: |
||||
|
Libs: -L${libdir} -l@CMAKE_PROJECT_NAME@ |
||||
|
Cflags: -I${includedir} |
@ -0,0 +1,198 @@ |
|||||
|
/*
|
||||
|
Copyright (c) 2012-2013 Martin Sustrik All rights reserved. |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), |
||||
|
to deal in the Software without restriction, including without limitation |
||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
|
and/or sell copies of the Software, and to permit persons to whom |
||||
|
the Software is furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included |
||||
|
in all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
||||
|
IN THE SOFTWARE. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef NN_PROTOCOL_INCLUDED |
||||
|
#define NN_PROTOCOL_INCLUDED |
||||
|
|
||||
|
#include "utils/msg.h" |
||||
|
#include "utils/list.h" |
||||
|
#include "utils/int.h" |
||||
|
|
||||
|
#include <stddef.h> |
||||
|
|
||||
|
struct nn_ctx; |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Pipe class. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* Any combination of following flags can be returned from successful call
|
||||
|
to nn_pipe_send or nn_pipe_recv. */ |
||||
|
|
||||
|
/* This flag means that the pipe can't be used for receiving (when returned
|
||||
|
from nn_pipe_recv()) or sending (when returned from nn_pipe_send()). |
||||
|
Protocol implementation should not send/recv messages from the pipe until |
||||
|
the pipe is revived by in()/out() function. */ |
||||
|
#define NN_PIPE_RELEASE 1 |
||||
|
|
||||
|
/* Specifies that received message is already split into header and body.
|
||||
|
This flag is used only by inproc transport to avoid merging and re-splitting |
||||
|
the messages passed with a single process. */ |
||||
|
#define NN_PIPE_PARSED 2 |
||||
|
|
||||
|
/* Events generated by the pipe. */ |
||||
|
#define NN_PIPE_IN 33987 |
||||
|
#define NN_PIPE_OUT 33988 |
||||
|
|
||||
|
struct nn_pipe; |
||||
|
|
||||
|
/* Associates opaque pointer to protocol-specific data with the pipe. */ |
||||
|
void nn_pipe_setdata (struct nn_pipe *self, void *data); |
||||
|
|
||||
|
/* Retrieves the opaque pointer associated with the pipe. */ |
||||
|
void *nn_pipe_getdata (struct nn_pipe *self); |
||||
|
|
||||
|
/* Send the message to the pipe. If successful, pipe takes ownership of the
|
||||
|
messages. */ |
||||
|
int nn_pipe_send (struct nn_pipe *self, struct nn_msg *msg); |
||||
|
|
||||
|
/* Receive a message from a pipe. 'msg' should not be initialised prior to
|
||||
|
the call. It will be initialised when the call succeeds. */ |
||||
|
int nn_pipe_recv (struct nn_pipe *self, struct nn_msg *msg); |
||||
|
|
||||
|
/* Get option for pipe. Mostly useful for endpoint-specific options */ |
||||
|
void nn_pipe_getopt (struct nn_pipe *self, int level, int option, |
||||
|
void *optval, size_t *optvallen); |
||||
|
|
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* Base class for all socket types. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
struct nn_sockbase; |
||||
|
|
||||
|
/* Any combination of these events can be returned from 'events' virtual
|
||||
|
function. */ |
||||
|
#define NN_SOCKBASE_EVENT_IN 1 |
||||
|
#define NN_SOCKBASE_EVENT_OUT 2 |
||||
|
|
||||
|
/* To be implemented by individual socket types. */ |
||||
|
struct nn_sockbase_vfptr { |
||||
|
|
||||
|
/* Ask socket to stop. */ |
||||
|
void (*stop) (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Deallocate the socket. */ |
||||
|
void (*destroy) (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Management of pipes. 'add' registers a new pipe. The pipe cannot be used
|
||||
|
to send to or to be received from at the moment. 'rm' unregisters the |
||||
|
pipe. The pipe should not be used after this call as it may already be |
||||
|
deallocated. 'in' informs the socket that pipe is readable. 'out' |
||||
|
informs it that it is writable. */ |
||||
|
int (*add) (struct nn_sockbase *self, struct nn_pipe *pipe); |
||||
|
void (*rm) (struct nn_sockbase *self, struct nn_pipe *pipe); |
||||
|
void (*in) (struct nn_sockbase *self, struct nn_pipe *pipe); |
||||
|
void (*out) (struct nn_sockbase *self, struct nn_pipe *pipe); |
||||
|
|
||||
|
/* Return any combination of event flags defined above, thus specifying
|
||||
|
whether the socket should be readable, writable, both or none. */ |
||||
|
int (*events) (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Send a message to the socket. Returns -EAGAIN if it cannot be done at
|
||||
|
the moment or zero in case of success. */ |
||||
|
int (*send) (struct nn_sockbase *self, struct nn_msg *msg); |
||||
|
|
||||
|
/* Receive a message from the socket. Returns -EAGAIN if it cannot be done
|
||||
|
at the moment or zero in case of success. */ |
||||
|
int (*recv) (struct nn_sockbase *self, struct nn_msg *msg); |
||||
|
|
||||
|
/* Set a protocol specific option. */ |
||||
|
int (*setopt) (struct nn_sockbase *self, int level, int option, |
||||
|
const void *optval, size_t optvallen); |
||||
|
|
||||
|
/* Retrieve a protocol specific option. */ |
||||
|
int (*getopt) (struct nn_sockbase *self, int level, int option, |
||||
|
void *optval, size_t *optvallen); |
||||
|
}; |
||||
|
|
||||
|
struct nn_sockbase { |
||||
|
const struct nn_sockbase_vfptr *vfptr; |
||||
|
struct nn_sock *sock; |
||||
|
}; |
||||
|
|
||||
|
/* Initialise the socket base class. 'hint' is the opaque value passed to the
|
||||
|
nn_transport's 'create' function. */ |
||||
|
void nn_sockbase_init (struct nn_sockbase *self, |
||||
|
const struct nn_sockbase_vfptr *vfptr, void *hint); |
||||
|
|
||||
|
/* Terminate the socket base class. */ |
||||
|
void nn_sockbase_term (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Call this function when stopping is done. */ |
||||
|
void nn_sockbase_stopped (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Returns the AIO context associated with the socket. This function is
|
||||
|
useful when socket type implementation needs to create async objects, |
||||
|
such as timers. */ |
||||
|
struct nn_ctx *nn_sockbase_getctx (struct nn_sockbase *self); |
||||
|
|
||||
|
/* Retrieve a NN_SOL_SOCKET-level option. */ |
||||
|
int nn_sockbase_getopt (struct nn_sockbase *self, int option, |
||||
|
void *optval, size_t *optvallen); |
||||
|
|
||||
|
/* Add some statistics for socket */ |
||||
|
void nn_sockbase_stat_increment (struct nn_sockbase *self, int name, |
||||
|
int increment); |
||||
|
|
||||
|
#define NN_STAT_CURRENT_SND_PRIORITY 401 |
||||
|
|
||||
|
/******************************************************************************/ |
||||
|
/* The socktype class. */ |
||||
|
/******************************************************************************/ |
||||
|
|
||||
|
/* This structure defines a class factory for individual socket types. */ |
||||
|
|
||||
|
/* Specifies that the socket type can be never used to receive messages. */ |
||||
|
#define NN_SOCKTYPE_FLAG_NORECV 1 |
||||
|
|
||||
|
/* Specifies that the socket type can be never used to send messages. */ |
||||
|
#define NN_SOCKTYPE_FLAG_NOSEND 2 |
||||
|
|
||||
|
struct nn_socktype { |
||||
|
|
||||
|
/* Domain and protocol IDs as specified in nn_socket() function. */ |
||||
|
int domain; |
||||
|
int protocol; |
||||
|
|
||||
|
/* Any combination of the flags defined above. */ |
||||
|
int flags; |
||||
|
|
||||
|
/* Function to create specific socket type. 'sockbase' is the output
|
||||
|
parameter to return reference to newly created socket. This function |
||||
|
is called under global lock, so it is not possible that two sockets are |
||||
|
being created in parallel. */ |
||||
|
int (*create) (void *hint, struct nn_sockbase **sockbase); |
||||
|
|
||||
|
/* Returns 1 if the supplied socket type is a valid peer for this socket,
|
||||
|
0 otherwise. Note that the validation is done only within a single |
||||
|
SP protocol. Peers speaking other SP protocols are discarded by the |
||||
|
core and socket is not even asked to validate them. */ |
||||
|
int (*ispeer) (int socktype); |
||||
|
|
||||
|
/* This member is owned by the core. Never touch it directly from inside
|
||||
|
the protocol implementation. */ |
||||
|
struct nn_list_item item; |
||||
|
}; |
||||
|
|
||||
|
#endif |
||||
|
|
@ -0,0 +1,2 @@ |
|||||
|
This directory contains all the available scalability protocol implementations, |
||||
|
such as publish/subscribe, request/reply etc. |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue