🚀 finish socket library:

socket.socket()

socket.closesocket()

socket.shutdown()

socket.bind()

socket.listen()

socket.connect()

socket.accept()

socket.send() socket.sendto()

socket.recv() socket.recvfrom()

socket.errno()
This commit is contained in:
ValKmjolnir 2022-06-08 19:06:16 +08:00
parent 53b85cd459
commit 12d7dde42d
7 changed files with 252 additions and 7 deletions

View File

@ -23,6 +23,7 @@ test:nasal
@ ./nasal -op -t -d test/fib.nas
@ ./nasal -op -e test/filesystem.nas
@ ./nasal -op -e -d test/hexdump.nas
@ ./nasal -op -c test/httptest.nas
@ ./nasal -op -e test/json.nas
@ ./nasal -op -e test/leetcode1319.nas
@ ./nasal -op -e -d test/lexer.nas

View File

@ -2,6 +2,16 @@ var socket=func(){
var lib=dylib.dlopen("./module/libnasock"~(os.platform()=="windows"?".dll":".so"));
var sock=dylib.dlsym(lib,"nas_socket");
var closesocket=dylib.dlsym(lib,"nas_closesocket");
var shutdown=dylib.dlsym(lib,"nas_shutdown");
var bind=dylib.dlsym(lib,"nas_bind");
var listen=dylib.dlsym(lib,"nas_listen");
var connect=dylib.dlsym(lib,"nas_connect");
var accept=dylib.dlsym(lib,"nas_accept");
var send=dylib.dlsym(lib,"nas_send");
var sendto=dylib.dlsym(lib,"nas_sendto");
var recv=dylib.dlsym(lib,"nas_recv");
var recvfrom=dylib.dlsym(lib,"nas_recvfrom");
var errno=dylib.dlsym(lib,"nas_errno");
var call=dylib.dlcall;
return {
AF_UNSPEC:0,AF_UNIX:1,AF_INET:2,AF_IMPLINK:3,
@ -27,11 +37,49 @@ var socket=func(){
IPPORT_EFSSERVER:520,IPPORT_BIFFUDP:512,IPPORT_WHOSERVER:513,IPPORT_ROUTESERVER:520,
IPPORT_RESERVED:1024,
SHUT_RD :0x00,
SHUT_WR :0x01,
SHUT_RDWR:0x02,
MSG_OOB:0x1,
MSG_PEEK:0x2,
MSG_DONTROUTE:0x4,
socket:func(af,type,proto){
return call(sock,af,type,proto);
},
closesocket:func(sd){
return call(closesocket,sd);
},
shutdown: func(sd,how){
return call(shutdown,sd,how);
},
bind: func(sd,ip,port){
return call(bind,sd,ip,port);
},
listen: func(sd,backlog){
return call(listen,sd,backlog);
},
connect: func(sd,hostname,port){
return call(connect,sd,hostname,port);
},
accept: func(sd){
return call(accept,sd);
},
send: func(sd,buff,flags=0){
return call(send,sd,buff,flags);
},
sendto: func(sd,hostname,port,buff,flags=0){
return call(sendto,sd,hostname,port,buff,flags);
},
recv: func(sd,len,flags=0){
return call(recv,sd,len,flags);
},
recvfrom: func(sd,len,flags=0){
return call(recvfrom,sd,len,flags);
},
errno: func(){
return call(errno);
}
};
}();

View File

@ -25,7 +25,7 @@ libnasock.dll: nasocket.cpp
clean:
rm *.o *.so *.dll *.dylib
all: libfib.so libkey.so
all: libfib.so libkey.so libnasock.so
@ echo "build done"
mingw-all: libfib.dll libkey.dll
mingw-all: libfib.dll libkey.dll libnasock.dll
@ echo "build done"

View File

@ -1,4 +1,5 @@
#include "../nasal.h"
#include <unistd.h>
#ifdef _WIN32
#include <winsock.h>
@ -18,12 +19,13 @@ public:
static WSAmanager win;
#else
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif
extern "C" nasal_ref nas_socket(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args.size()!=3)
return builtin_err("socket","invalid arguments");
if(args[0].type!=vm_num || args[1].type!=vm_num || args[2].type!=vm_num)
return builtin_err("socket","\"af\", \"type\", \"protocol\" should be number");
int sd=socket(args[0].num(),args[1].num(),args[2].num());
@ -31,8 +33,6 @@ extern "C" nasal_ref nas_socket(std::vector<nasal_ref>& args,nasal_gc& gc){
}
extern "C" nasal_ref nas_closesocket(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args.size()!=1)
return builtin_err("closesocket","invalid arguments");
if(args[0].type!=vm_num)
return builtin_err("closesocket","\"\" should be number");
#ifdef _WIN32
@ -40,4 +40,162 @@ extern "C" nasal_ref nas_closesocket(std::vector<nasal_ref>& args,nasal_gc& gc){
#else
return {vm_num,(double)close(args[0].num())};
#endif
}
extern "C" nasal_ref nas_shutdown(std::vector<nasal_ref>& args,nasal_gc& gc){
//shutdown();
if(args[0].type!=vm_num)
return builtin_err("shutdown","\"sd\" must be a number");
if(args[1].type!=vm_num)
return builtin_err("shutdown","\"how\" must be a number");
return {vm_num,(double)shutdown(args[0].num(),args[1].num())};
}
extern "C" nasal_ref nas_bind(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args[0].type!=vm_num)
return builtin_err("bind","\"sd\" muse be a number");
if(args[1].type!=vm_str)
return builtin_err("bind","\"ip\" should be a string including an ip with correct format");
if(args[2].type!=vm_num)
return builtin_err("bind","\"port\" must be a number");
sockaddr_in server;
memset(&server,0,sizeof(sockaddr_in));
server.sin_family=AF_INET;
server.sin_addr.s_addr=inet_addr(args[1].str().c_str());
server.sin_port=htons(args[2].num());
return {vm_num,(double)bind(args[0].num(),(sockaddr*)&server,sizeof(server))};
}
extern "C" nasal_ref nas_listen(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args[0].type!=vm_num)
return builtin_err("listen","\"sd\" must be a number");
if(args[1].type!=vm_num)
return builtin_err("listen","\"backlog\" must be a number");
return{vm_num,(double)listen(args[0].num(),args[1].num())};
}
extern "C" nasal_ref nas_connect(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args[0].type!=vm_num)
return builtin_err("connect","\"sd\" must be a number");
if(args[1].type!=vm_str)
return builtin_err("connect","\"hostname\" must be a string");
if(args[2].type!=vm_num)
return builtin_err("connect","\"port\" must be a number");
sockaddr_in addr;
memset(&addr,0,sizeof(sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_port=htons(args[2].num());
hostent* entry=gethostbyname(args[1].str().c_str());
memcpy(&addr.sin_addr,entry->h_addr,entry->h_length);
return {vm_num,(double)connect(args[0].num(),(sockaddr*)&addr,sizeof(sockaddr_in))};
}
extern "C" nasal_ref nas_accept(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args[0].type!=vm_num)
return builtin_err("accept","\"sd\" must be a number");
sockaddr_in client;
int socklen=sizeof(sockaddr_in);
#ifdef _WIN32
int client_sd=accept(args[0].num(),(sockaddr*)&client,&socklen);
#else
int client_sd=accept(args[0].num(),(sockaddr*)&client,(socklen_t*)&socklen);
#endif
if(gc.top+1>=gc.canary)
return builtin_err("accept","expand temporary space error:stackoverflow");
(++gc.top)[0]=gc.alloc(vm_hash);
auto& hash=gc.top[0].hash().elems;
hash["sd"]={vm_num,(double)client_sd};
hash["ip"]=gc.alloc(vm_str);
hash["ip"].str()=inet_ntoa(client.sin_addr);
--gc.top;
return gc.top[1];
}
extern "C" nasal_ref nas_send(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args[0].type!=vm_num)
return builtin_err("send","\"sd\" must be a number");
if(args[1].type!=vm_str)
return builtin_err("send","\"buff\" must be a string");
if(args[2].type!=vm_num)
return builtin_err("send","\"flags\" muse be a number");
return {vm_num,(double)send(args[0].num(),args[1].str().c_str(),args[1].str().length(),args[2].num())};
}
extern "C" nasal_ref nas_sendto(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args[0].type!=vm_num)
return builtin_err("sendto","\"sd\" must be a number");
if(args[1].type!=vm_str)
return builtin_err("sendto","\"hostname\" must be a string");
if(args[2].type!=vm_num)
return builtin_err("sendto","\"port\" must be a number");
if(args[3].type!=vm_str)
return builtin_err("sendto","\"buff\" must be a string");
if(args[4].type!=vm_num)
return builtin_err("sendto","\"flags\" must be a number");
sockaddr_in addr;
memset(&addr,0,sizeof(sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_port=htons(args[2].num());
hostent* entry=gethostbyname(args[1].str().c_str());
memcpy(&addr.sin_addr,entry->h_addr,entry->h_length);
return {vm_num,(double)sendto(args[0].num(),args[3].str().c_str(),args[3].str().length(),args[4].num(),(sockaddr*)&addr,sizeof(sockaddr_in))};
}
extern "C" nasal_ref nas_recv(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args[0].type!=vm_num)
return builtin_err("recv","\"sd\" must be a number");
if(args[1].type!=vm_num)
return builtin_err("recv","\"len\" must be a number");
if(args[1].num()<=0 || args[1].num()>16*1024*1024)
return builtin_err("recv","\"len\" out of range");
if(args[2].type!=vm_num)
return builtin_err("recv","\"flags\" muse be a number");
if(gc.top+1>=gc.canary)
return builtin_err("recv","expand temporary space error:stackoverflow");
(++gc.top)[0]=gc.alloc(vm_hash);
auto& hash=gc.top[0].hash().elems;
hash["str"]=gc.alloc(vm_str);
char* buf=new char[(int)args[1].num()];
hash["size"]={vm_num,(double)recv(args[0].num(),buf,args[1].num(),args[2].num())};
hash["str"].str()=buf;
delete[] buf;
--gc.top;
return gc.top[1];
}
extern "C" nasal_ref nas_recvfrom(std::vector<nasal_ref>& args,nasal_gc& gc){
if(args[0].type!=vm_num)
return builtin_err("recvfrom","\"sd\" must be a number");
if(args[1].type!=vm_num)
return builtin_err("recvfrom","\"len\" must be a number");
if(args[1].num()<=0 || args[1].num()>16*1024*1024)
return builtin_err("recvfrom","\"len\" out of range");
if(args[2].type!=vm_num)
return builtin_err("recvfrom","\"flags\" muse be a number");
if(gc.top+1>=gc.canary)
return builtin_err("recvfrom","expand temporary space error:stackoverflow");
sockaddr_in addr;
int socklen=sizeof(sockaddr_in);
(++gc.top)[0]=gc.alloc(vm_hash);
auto& hash=gc.top[0].hash().elems;
hash["str"]=gc.alloc(vm_str);
char* buf=new char[(int)args[1].num()+1];
#ifdef _WIN32
hash["size"]={vm_num,(double)recvfrom(args[0].num(),buf,args[1].num(),args[2].num(),(sockaddr*)&addr,&socklen)};
#else
hash["size"]={vm_num,(double)recvfrom(args[0].num(),buf,args[1].num(),args[2].num(),(sockaddr*)&addr,(socklen_t*)&socklen)};
#endif
buf[(int)hash["size"].num()]=0;
hash["str"].str()=buf;
delete[] buf;
hash["fromip"]=gc.alloc(vm_str);
hash["fromip"].str()=inet_ntoa(addr.sin_addr);
--gc.top;
return gc.top[1];
}
extern "C" nasal_ref nas_errno(std::vector<nasal_ref>& args,nasal_gc& gc){
nasal_ref res=gc.alloc(vm_str);
res.str()=strerror(errno);
return res;
}

View File

@ -44,6 +44,7 @@ var testfile=[
"test/fib.nas ",
"test/filesystem.nas ",
"test/hexdump.nas ",
"test/httptest.nas ",
"test/json.nas ",
"test/leetcode1319.nas ",
"test/lexer.nas ",
@ -73,8 +74,10 @@ var testfile=[
var module=[
"module/fib.cpp ",
"module/keyboard.cpp ",
"module/nasocket.cpp ",
"module/libfib.nas ",
"module/libkey.nas "
"module/libkey.nas ",
"module/libsock.nas "
];
var getname=func(s){

34
test/httptest.nas Normal file
View File

@ -0,0 +1,34 @@
import("module/libsock.nas");
var sd=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_IP);
socket.bind(sd,"127.0.0.1",8080);
socket.listen(sd,1);
var client=socket.accept(sd);
println("request ip: ",client.ip);
var rv=socket.recv(client.sd,1024);
println(rv.str);
socket.send(client.sd,"Http/1.1 200 OK
<html>
<head>
<title> nasal-http-test-web </title>
</head>
<body>
<text>
Hello, this is a simple HTML document just for test.<br />
This simple http server is written in nasal.<br />
Nasal is an ECMAscript-like programming language that used in Flightgear.<br />
This language is designed by Andy Ross.<br />
The interpreter is totally rewritten by ValKmjolnir using C++(-std=c++11) without reusing the code in Andy Ross's nasal interpreter.<br />
But we really appreciate that Andy created this amazing programming language and his interpreter project.<br />
Now this project uses MIT license(2021/5/4). Edit it if you want, use this project to learn or create more interesting things(But don't forget me XD).
</text>
</body>
</html>
");
socket.closesocket(client.sd);
socket.closesocket(sd);

View File

@ -75,6 +75,7 @@ var filechecksum=func(){
"./test/fib.nas ",
"./test/filesystem.nas ",
"./test/hexdump.nas ",
"./test/httptest.nas ",
"./test/json.nas ",
"./test/leetcode1319.nas ",
"./test/lexer.nas ",