您的位置:首页 > 移动开发

appweb的JavaScript调用C函数的实现过程(以设置eth0 IP地址为例)

2011-08-04 10:52 435 查看
appweb的独到之处:EJS调用底层的C函数的实现代码:

appweb-src-2.4.1\doc\guide\appweb\users\ejs\extending.html

appweb-src-2.4.1-latest\appweb-src-2.4.1\doc\api\gen\appweb\overview.html

可以结合: 源码\samples\C++\simpleModule以及 源码\samples\C\simpleEsp目录里的文件来学习。

C++ 代码(ethernetModule.cpp):

#include "ethernetModule.h"

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <sys/ioctl.h>

#include <net/if.h>

static int set_ipaddr(const int sockfd, const char *ifname, char *ip);

static int set_netmask(const int sockfd, const char *ifname, char *netmask);

int mprEthernetModuleInit(void *handle)

{

new EthernetModule(handle);

return 0;

}

EthernetModule::EthernetModule(void *handle) : MaModule("ethernetModule", handle)

{

//这里将我们的C函数setEthernet()与EJS(Embedded JavaScript)函数setEthernet()绑定,这样我们在ESP就可以调用底层的C函数了。

espDefineStringCFunction(0, "setEthernet", setEthernet, 0);

}

EthernetModule::~EthernetModule()

{

}

int EthernetModule::parseConfig(char *key, char *value, MaServer *server,

MaHost *host, MaAuth *auth, MaDir* dir, MaLocation *location)

{

if (mprStrCmpAnyCase(key, "ethernetDirective") == 0)

return 1;

return 0;

}

int EthernetModule::start()

{

return 0;

}

void EthernetModule::stop()

{

}

/*

* Function : Set IP address, netmask for eth1

* Usage : setEthernet(ipaddr, netmask);

* Return value : MprVar status

*/

static int setEthernet(EspRequest *ep, int argc, char **argv)

{

char *ifname="eth1";

char *ip, *netmask;

int sockfd, ret;

struct in_addr addr;

MprVar status;

status = espCreateObjVar("setStatusObj", 0);

ip = argv[0];

netmask = argv[1];

if( (ret=inet_pton(AF_INET, ip, &addr)<=0) || (ret=inet_pton(AF_INET, netmask, &addr)<=0) )

{

status = mprCreateIntegerVar(0);

goto ret;

}

if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)

{

status = mprCreateIntegerVar(0);

goto ret;

}

if ((!set_ipaddr(sockfd, ifname, ip)) || (!set_netmask(sockfd, ifname, netmask)) )

{

status = mprCreateIntegerVar(0);

goto ret;

}

status = mprCreateIntegerVar(1);

ret:

espSetReturn(ep, status);

espDestroyVar(&status);

return 0;

}

static int set_ipaddr(const int sockfd, const char *ifname, char *ip)

{

struct sockaddr_in addr;

struct ifreq ifr;

int ret = 1; //set status: 0->Failture 1->Success

bzero(&addr, sizeof(addr));

addr.sin_family = AF_INET;

inet_aton(ip,&addr.sin_addr);

strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);

memcpy(&ifr.ifr_addr,(struct sockaddr *)&addr, sizeof(addr));

if(ioctl(sockfd, SIOCSIFADDR, &ifr) == -1)

ret = 0;

return ret;

}

static int set_netmask(const int sockfd, const char *ifname, char *netmask)

{

struct sockaddr_in addr;

struct ifreq ifr;

int ret = 1; //set status: 0->Failture 1->Success

bzero(&addr, sizeof(addr));

addr.sin_family = PF_INET;

inet_aton(netmask,&addr.sin_addr);

strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);

memcpy(&ifr.ifr_netmask,(struct sockaddr *)&addr, sizeof(addr));

if(ioctl(sockfd, SIOCSIFNETMASK, &ifr) == -1)

ret = 0;

return ret;

}

上层的EJS网页代码(ethernetSet.esp):

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>Set ethernet IP address</title>

</head>

<body>

<%if(session['username']){%> //判断用户是否登录,如果登录就显示该页

<div class="mainTitle marginAuto" id="title">Ethernet IP Setting</div>

<div class="mainBox marginAuto">

<div class="mainContent">

<div class="innerContent">

<form method="POST" action="@@request['SCRIPT_NAME']" > //提交表单

<table class="inputForm" border=0>

<tr>

<td><b>IP Address</b></td>

<td><input name="ip" type="text" value="@@form['ip']" onBlur="validIP(this,0);"></td>

</tr>

<tr>

<td><b>Netmask</b></td>

<td><input name="netmask" type="text" value="@@form['netmask']" onBlur="validIP(this,1)"></td>

</tr>

</table>

<input type="submit" value="Submit">

<input type="reset" value="Reset">

</form>

<%

if (request["REQUEST_METHOD"] == "POST") //处理提交的表单

{

var ret;

//form['ip']为表单提交的值,并调用上面写的C代码来设置IP地址,这里底层的C函数能返回MprVar(Object)类型值,或string。

ret = setEthernet(form['ip'], form['netmask']);

if(0 == ret)

write("Set failure: Make sure the input IP address is a valid IPv4 address.</br>");

else

{

write("The set IP address: " + form['ip'] + "</br>");

write("The set netmask address: " + form['netmask'] + "</br>");

}

}

%>

</div>

</div>

</div>

<%

}

else

{

redirect("login.esp"); //如果没登录,就转到login.esp去登录。

}

%>

</body>

</html>

上面的C++函数需要编译成动态库,然后在appweb.conf里加载这个模块,使这个函数作为appweb的一部分,这样方能使用EJS调用底层的C函数。

在appweb-src-2.4.1\samples\C++\simpleModule 拷贝一份,并更名为ethernetModule,将上面的ethernetModule.cpp 源代码放到该目录下,并将所有文件里的simpleModule改为ethernetModule(注意有大小写)。参考simpleModule改。

然后执行make,如果是交叉编译,他会到找上层Makefile中设置的交叉编译器来进行交叉编译。Make后会得到ethernetModule.so,将其更名为libethernetModule.so并放到appweb指定的动态库路径下,也可以通过LD_LIBRARY_PATH环境变量来指定。

修改appweb.conf (118行左右)为:

LoadModulePath "../lib/arm-atmel-linux/modules"

#这个路径即为appweb寻找动态库的路径,也可以通过LD_LIBRARY_PATH环境变量来指定。

LoadModule ethernetModule libethernetModule

<if SSL_MODULE>

LoadModule ssl libsslModule

<if MATRIXSSL_MODULE>

LoadModule matrixSsl libmatrixSslModule

</if>

<if OPENSSL_MODULE>

LoadModule openSsl libopenSslModule

</if>

</if>

重启appweb,这时appweb就会像加载所有其他模块一样(如matrixssl)一样加载我们的ethernetModule.so(可以通过看logs/error.log检查是否加载成功).这样就可以在ethernetSet.esp顺利的调用 ret = setEthernet(form['ip'], form['netmask']);

顺便提一句: appweb和我们的c/c++程序都是运行在同一个进程环境下,这样我们必须保证我们的C/C++代码不能出现任何错误(段错误)导致进程退出。有一次,我就在一行C代码里调用了exit(),结果每导致执行一次该页面,服务器就down掉一次
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: