#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行左右)为: