-
Notifications
You must be signed in to change notification settings - Fork 11
/
net.c
140 lines (137 loc) · 4.03 KB
/
net.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// NETWORKING
#include "def.h"
#include "proto.h"
#include "accessors.h"
#include "vary.h"
#ifdef STDLIBNET
#define NETLOOPBLK IOBLOCKSZ
int netr(int sock,void* b,size_t maxl) {
return read(sock,b,maxl); // TODO chunk
}
VP netw(int sock,VP buf) {
XRAY_log("netw %d\n",sock);XRAY_emit(buf);
if(buf==NULL) return NULL;
if(!IS_b(buf)&&!IS_c(buf)) return EXC(Tt(type),"netw only strings",xi(sock),buf);
if(write(sock,BUF(buf),buf->n)<buf->n) PERR("netw");
return NULL;
}
VP netcall(VP data,VP addr) {
int sock=socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sin={0}; sin.sin_family=AF_INET; // TODO IPv6
int port=AS_i(ELl(addr,0),0); sin.sin_port=htons(port);
if(LEN(addr) > 1 && IS_c(ELl(addr,1))) {
char host[64]={0};
strncpy(host,bfromx(ELl(addr,1)),64);
struct hostent* server=gethostbyname(host);
if(server==NULL)return EXC(Tt(host),"hostname not found",data,addr);
bcopy((char*)server->h_addr,(char*)&sin.sin_addr.s_addr,server->h_length);
}
if(connect(sock,(struct sockaddr *)&sin, sizeof(sin)) < 0) {
char* err=malloc(256); int len;
snprintf(err,256,"couldn't connect to host/port: ");
len=strlen(err);
strerror_r(errno, err+len, 256-len);
return EXC(Tt(call),err,data,addr);
}
VP w=netw(sock,data); if(w) return w;
char input[NETLOOPBLK]={0};
int nread=netr(sock, input, NETLOOPBLK-1);
shutdown(sock,SHUT_RDWR); close(sock);
if(nread>0) { // dont i have a primitive for this
VP res=xcsz(nread); memmove(BUF(res),input,nread); res->n=nread; return res;
} else return NULL;
}
VP netserve(VP sockcb) {
int sock=AS_i(LIST_item(sockcb,0),0), nread;
VP cb=LIST_item(sockcb,1);
VP resp, t1, t2, t3;
char input[NETLOOPBLK];
/*
if(remotea.sa_family==AF_INET)
ip = inet_ntoa(((struct sockaddr_in *)&remotea)->sin_addr);
else
ip = "n/a";
*/
XRAY_log("new connection %d\n",sock);
memset(input, 0, NETLOOPBLK);
nread=netr(sock, input, NETLOOPBLK-1);
XRAY_log("read result %d\n", nread);
if(nread > 0) {
t1=xfroms(input); t2=xfroms("n/a"); t3=xln(2,t1,t2);
resp=apply(cb,t3);
xfree(t3);xfree(t2);xfree(t1);
XRAY_log("netloop handler resp for %d\n",sock); XRAY_emit(resp);
if(resp!=NULL && !IS_c(resp)) {
XRAY_log("massaging\n");XRAY_emit(resp);
resp=repr(resp);
}
netw(sock,resp);
xfree(resp);
}
shutdown(sock,SHUT_RDWR);
XRAY_log("netloop closing %d\n",sock);
close(sock);
return NULL;
}
VP netloop(VP xsock,VP cb) {
int cons;
struct sockaddr remotea={0};
socklen_t remotel={0};
int sock=AS_i(xsock,0);
int n=0;
printf("netloop starting..\n");
XRAY_emit(xsock);
XRAY_emit(cb);
for(;;) {
printf(".");
cons=accept(sock, &remotea, &remotel);
netserve(xln(2,xi(cons),cb));
// thr_run1(x1(&netserve),xln(2,xi(cons),cb));
n++;
}
XRAY_log("netloop closing sock after %d\n",n);
close(sock);
return xl0();
}
VP netbind(VP opts,VP cb) {
XRAY_log("netbind\n");XRAY_emit(opts);XRAY_emit(cb);
if(!LIST(opts)) return EXC(Tt(type),"bad network bind options",opts,cb);
int sock, opt, port;
char host[64];
struct linger lf= {0};
struct sockaddr_in sin= {0};
struct sockaddr remote;
socklen_t remotel;
sock=socket(sin.sin_family=AF_INET,SOCK_STREAM,IPPROTO_TCP);
opt=1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
/*
lf.l_onoff=1;
lf.l_linger=0;
setsockopt(sock,SOL_SOCKET,SO_LINGER,&lf,sizeof(lf));
*/
//opt=5; setsockopt(sock,SOL_TCP,TCP_DEFER_ACCEPT,&opt,sizeof(opt));
if(!IS_i(ELl(opts,0))) return EXC(Tt(port),"bad port",opts,cb);
port=AS_i(ELl(opts,0),0);
sin.sin_port=htons(port);
if(ELl(opts,1)->n >= 1 && IS_c(ELl(opts,1))) {
strncpy(host,bfromx(ELl(opts,1)),64);
if(inet_aton(host,&sin.sin_addr)==-1)return EXC(Tt(host),"hostname not found",opts,cb);
}
if(bind(sock,(struct sockaddr*)&sin,sizeof(sin))) {
char* err=malloc(256); int len;
snprintf(err,256,"couldn't bind to host/port: ");
len=strlen(err);
strerror_r(errno, err+len, 256-len);
return EXC(Tt(bind),err,opts,cb);
}
listen(sock, 10); // XXX smarter listen backlog
xref(cb);
VP xsock=xi(sock);
xref(xsock);
thr_run(proj(2,&netloop,xsock,cb));
printf("net booted\n");
XRAY_emit(cb);
return opts;
}
#endif