mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
161 lines
5.1 KiB
C
161 lines
5.1 KiB
C
/*
|
|
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
|
*
|
|
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
* Implementation of JsNetwork that calls into JavaScript
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
#include "jsinteractive.h"
|
|
#include "network.h"
|
|
#include "network_js.h"
|
|
#include "jswrap_stream.h"
|
|
|
|
#define JSNET_NAME "JSN"
|
|
#define JSNET_DNS_NAME "DNS"
|
|
|
|
// Set the built-in object for network access
|
|
void net_js_setObj(JsVar *obj) {
|
|
jsvObjectSetChild(execInfo.hiddenRoot, JSNET_NAME, obj);
|
|
}
|
|
|
|
/// Call the named function on the object - whether it's built in, or predefined. Returns the return value of the function.
|
|
JsVar *callFn(char* name, int argCount, JsVar **argPtr) {
|
|
JsVar *netObj = jsvObjectGetChild(execInfo.hiddenRoot, JSNET_NAME, 0);
|
|
JsVar *child = jspGetNamedField(netObj, name, false);
|
|
|
|
JsVar *r = 0;
|
|
if (jsvIsFunction(child)) {
|
|
JsExecInfo oldExecInfo = execInfo;
|
|
execInfo.execute = EXEC_YES;
|
|
r = jspeFunctionCall(child, 0, netObj, false, argCount, argPtr);
|
|
execInfo = oldExecInfo;
|
|
}
|
|
jsvUnLock2(child, netObj);
|
|
return r;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------
|
|
|
|
/// Get an IP address from a name. Sets out_ip_addr to 0 on failure
|
|
void net_js_gethostbyname(JsNetwork *net, char * hostName, uint32_t* out_ip_addr) {
|
|
NOT_USED(net);
|
|
// hacky - save the last checked name so we can put it straight into the request
|
|
*out_ip_addr = 0xFFFFFFFF;
|
|
jsvObjectSetChildAndUnLock(execInfo.hiddenRoot, JSNET_DNS_NAME, jsvNewFromString(hostName));
|
|
}
|
|
|
|
/// Called on idle. Do any checks required for this device
|
|
void net_js_idle(JsNetwork *net) {
|
|
NOT_USED(net);
|
|
}
|
|
|
|
/// Call just before returning to idle loop. This checks for errors and tries to recover. Returns true if no errors.
|
|
bool net_js_checkError(JsNetwork *net) {
|
|
NOT_USED(net);
|
|
return true;
|
|
}
|
|
|
|
/// if host=0, creates a server otherwise creates a client (and automatically connects). Returns >=0 on success
|
|
int net_js_createsocket(JsNetwork *net, uint32_t host, unsigned short port, SocketType socketType) {
|
|
NOT_USED(net);
|
|
JsVar *hostVar = 0;
|
|
if (host!=0) {
|
|
// client
|
|
if (host==0xFFFFFFFF) {
|
|
hostVar = jsvObjectGetChild(execInfo.hiddenRoot, JSNET_DNS_NAME, 0);
|
|
}
|
|
if (!hostVar)
|
|
hostVar = networkGetAddressAsString((unsigned char *)&host, 4,10,'.');
|
|
}
|
|
// else server, hostVar=0
|
|
JsVar *args[2] = {
|
|
hostVar,
|
|
jsvNewFromInteger(port)
|
|
};
|
|
int sckt = jsvGetIntegerAndUnLock(callFn("create", 2, args));
|
|
jsvUnLockMany(2, args);
|
|
return sckt;
|
|
}
|
|
|
|
/// destroys the given socket
|
|
void net_js_closesocket(JsNetwork *net, int sckt) {
|
|
NOT_USED(net);
|
|
JsVar *args[1] = {
|
|
jsvNewFromInteger(sckt)
|
|
};
|
|
jsvUnLock2(callFn("close", 1, args), args[0]);
|
|
}
|
|
|
|
/// If the given server socket can accept a connection, return it (or return < 0)
|
|
int net_js_accept(JsNetwork *net, int serverSckt) {
|
|
NOT_USED(net);
|
|
JsVar *netObj = jsvObjectGetChild(execInfo.hiddenRoot, JSNET_NAME, 0);
|
|
JsVar *args[1] = {
|
|
jsvNewFromInteger(serverSckt)
|
|
};
|
|
|
|
int sckt = jsvGetIntegerAndUnLock(callFn("accept", 1, args));
|
|
jsvUnLock2(args[0], netObj);
|
|
return sckt;
|
|
}
|
|
|
|
/// Receive data if possible. returns nBytes on success, 0 on no data, or -1 on failure
|
|
int net_js_recv(JsNetwork *net, int sckt, void *buf, size_t len) {
|
|
NOT_USED(net);
|
|
JsVar *args[2] = {
|
|
jsvNewFromInteger(sckt),
|
|
jsvNewFromInteger((JsVarInt)len),
|
|
};
|
|
JsVar *res = callFn( "recv", 2, args);
|
|
jsvUnLockMany(2, args);
|
|
int r = -1; // fail
|
|
if (jsvIsString(res)) {
|
|
r = (int)jsvGetStringLength(res);
|
|
if (r>(int)len) { r=(int)len; assert(0); }
|
|
jsvGetStringChars(res, 0, (char*)buf, (size_t)r);
|
|
// FIXME: jsvGetStringChars adds a 0 - does that actually write past the end of the array, or clip the data we get?
|
|
} else if (jsvIsInt(res)) {
|
|
r = jsvGetInteger(res);
|
|
if (r>=0) {
|
|
jsExceptionHere(JSET_ERROR, "JSNetwork.recv returned >=0");
|
|
r=-1;
|
|
}
|
|
}
|
|
jsvUnLock(res);
|
|
return r;
|
|
}
|
|
|
|
/// Send data if possible. returns nBytes on success, 0 on no data, or -1 on failure
|
|
int net_js_send(JsNetwork *net, int sckt, const void *buf, size_t len) {
|
|
NOT_USED(net);
|
|
JsVar *args[2] = {
|
|
jsvNewFromInteger(sckt),
|
|
jsvNewFromEmptyString()
|
|
};
|
|
jsvAppendStringBuf(args[1], buf, len);
|
|
int r = jsvGetIntegerAndUnLock(callFn( "send", 2, args));
|
|
jsvUnLockMany(2, args);
|
|
return r;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------
|
|
|
|
void netSetCallbacks_js(JsNetwork *net) {
|
|
net->idle = net_js_idle;
|
|
net->checkError = net_js_checkError;
|
|
net->createsocket = net_js_createsocket;
|
|
net->closesocket = net_js_closesocket;
|
|
net->accept = net_js_accept;
|
|
net->gethostbyname = net_js_gethostbyname;
|
|
net->recv = net_js_recv;
|
|
net->send = net_js_send;
|
|
net->chunkSize = 536;
|
|
}
|
|
|