summaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2011-10-08 20:30:28 +0200
committerHenrik Rydberg <rydberg@euromail.se>2011-10-08 20:30:28 +0200
commit5df79c53745fde5d6c3340a2979b1429cd5892c1 (patch)
tree1a81af141708b826e9c61e8a04019994fcca8298 /src/net
Initial import of htcd system 1.0
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'src/net')
-rw-r--r--src/net/htcd.cc153
-rw-r--r--src/net/isocket.cc58
-rw-r--r--src/net/isocket.h68
-rw-r--r--src/net/redirect.cc185
-rw-r--r--src/net/route80.cc64
-rw-r--r--src/net/server.cc75
-rw-r--r--src/net/server.h46
-rw-r--r--src/net/test.cc44
-rw-r--r--src/net/thrserv.cc255
-rw-r--r--src/net/thrserv.h79
10 files changed, 1027 insertions, 0 deletions
diff --git a/src/net/htcd.cc b/src/net/htcd.cc
new file mode 100644
index 0000000..89729e6
--- /dev/null
+++ b/src/net/htcd.cc
@@ -0,0 +1,153 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <net/thrserv.h>
21
22static fp_stream merr(stderr);
23
24static mstring PATH;
25static htcServ* SERV;
26
27const mstring PIDURI="/sys/htcd";
28
29const int BACKLOG=4;
30const int SERVERS=9;
31const int LOWER=3;
32const int UPPER=6;
33const int KEEPALIVE=300;
34const int SNDBUFSIZE=16384;
35const int RCVBUFSIZE=16384;
36
37///////////////////////////////////////////////////////////
38
39static thrServ* server[SERVERS];
40static thrCron* crontab;
41
42extern "C" {
43 static void* thr_handler(void* p) { ((thrServ*)p)->enter(); return 0; }
44 static void* thr_cron(void* p) { ((thrCron*)p)->enter(); return 0; }
45 static void onTERM(int sig) { SERV->htcd.running=0; }
46 static void onHUP(int sig) { if(crontab) crontab->running=0; }
47 typedef void (*disp_t)(int);
48}
49
50static void MainProc(isocket& sock)
51{
52 int keep=1;
53 while(SERV->htcd.running) {
54 int nvacant=0; for(int i=0;i<SERVERS;i++) if(server[i]->vacant()) nvacant++;
55 if(nvacant>UPPER) keep=1; else if(nvacant<=LOWER) keep=0;
56 if(!keep) for(int i=0;i<SERVERS;i++) server[i]->shutdown();
57 time_t timeout=time(0)-KEEPALIVE;
58 for(int i=0;i<SERVERS;i++) if(timeout>server[i]->last) server[i]->disconnect();
59 int test=sock.test();
60 if(test>0) {
61 thrServ* p=0;
62 for(int i=0;i<SERVERS;i++) if(server[i]->vacant()) { p=server[i]; break; }
63 if(!p) for(int i=0;i<SERVERS;i++) if(!p||server[i]->first<p->first) p=server[i];
64 if(p->shutdown()) {
65 try {
66 isocket* s=sock.accept();
67 if(s) p->reset(s,keep);
68 }
69 catch(const merror_t& e) {
70 merr<<"SOCKET: "<<e.desc<<"\n";
71 }
72 }
73 }
74 else if(test<0) SERV->htcd.running=0;
75 }
76 for(int i=0;i<SERVERS;i++) {
77 server[i]->term();
78 pthread_join(server[i]->ptid,0);
79 }
80 pthread_kill(crontab->tid,SIGHUP);
81 pthread_join(crontab->ptid,0);
82}
83
84///////////////////////////////////////////////////////////////
85
86static void httpServer(int overport)
87{
88 isocket sock(SERV->htcd.node.addr,overport,BACKLOG);
89 sock.keepalive(1);
90 sock.sendbufsize(SNDBUFSIZE);
91 sock.recvbufsize(RCVBUFSIZE);
92
93 sigignore(SIGPIPE);
94 disp_t onterm=signal(SIGTERM,onTERM);
95 disp_t onint=signal(SIGINT,onTERM);
96 disp_t onhup=signal(SIGHUP,onHUP);
97 MainProc(sock);
98 signal(SIGHUP,onhup);
99 signal(SIGINT,onint);
100 signal(SIGTERM,onterm);
101}
102
103static void Daemon(int overport) try
104{
105 PROCLOCK(PATH+PIDURI);
106 SERV=new htcServ(PATH);
107 crontab=new thrCron(*SERV);
108 pthread_create(&crontab->ptid,0,thr_cron,crontab);
109 for(int i=0;i<SERVERS;i++) {
110 server[i]=new thrServ(*SERV);
111 pthread_create(&server[i]->ptid,0,thr_handler,server[i]);
112 }
113 merr<<"htcd: "<<PATH<<" started\n";
114 httpServer(overport<0?0:overport==0?SERV->htcd.port:overport);
115 merr<<"htcd: "<<PATH<<" terminating\n";
116 for(int i=0;i<SERVERS;i++) delete server[i];
117 delete crontab;
118}
119catch(const merror_t& e) {
120 if(SERV) {
121 SERV->htcd.errlog<<"["<<time(0)<<"][MAIN]["<<e.desc<<"]\n";
122 merr<<e.desc<<"\n";
123 }
124 else if(First(e.desc)!=sref("proclock:")) merr<<e.desc<<"\n";
125}
126catch(...) {
127 if(SERV) SERV->htcd.errlog<<"["<<time(0)<<"][MAIN][FATAL]\n";
128 merr<<"FATAL\n";
129}
130
131main(int argc,char* argv[]) try
132{
133 if(argc<3) {
134 merr<<"Usage: "<<argv[0]<<" <path> <overport=-1|0|port> [-1|0|1]\n";
135 return -1;
136 }
137 PATH=argv[1]; if(PATH.back()=='/') PATH=PATH.popb();
138 setenv("DOCROOT",PATH.c_str(),1);
139 int overport=atoi(argv[2]);
140 int cmd=argc>3?atoi(argv[3]):0;
141 if(cmd) ProcTerminate(PATH+PIDURI);
142 if(cmd>=0) { if(fork()==0) Daemon(overport); }
143 delete SERV;
144 return 0;
145}
146catch(const merror_t& e) {
147 merr<<"ERROR: ["<<e.desc<<"]\n";
148 return -1;
149}
150catch(...) {
151 merr<<"ERROR: [FATAL]\n";
152 return -1;
153}
diff --git a/src/net/isocket.cc b/src/net/isocket.cc
new file mode 100644
index 0000000..af94189
--- /dev/null
+++ b/src/net/isocket.cc
@@ -0,0 +1,58 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <net/isocket.h>
21#include <errno.h>
22
23isocket::isocket(const in_addr& ia,int port,int backlog):
24 pipe_stream(-1),rd(-1)
25{
26 if(port) {
27 fd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
28 if(fd<0) THROW("isocket: Could not create");
29 reuse(1);
30 }
31 else fd=0;
32 sa.sin_family=2;
33 sa.sin_port=htons(port);
34 sa.sin_addr=ia;
35 if(port) {
36 if(bind(fd,(sockaddr*)&sa,sizeof(sa))==-1) THROW("isocket: Could not bind");
37 }
38 if(listen(fd,backlog)==-1) THROW("isocket: Could not listen");
39 rd.setfd(fd);
40}
41
42isocket::isocket(int f,const sockaddr_in& ia):
43 pipe_stream(f),rd(f)
44{
45 sa=ia;
46 setflag(O_NONBLOCK|O_NDELAY);
47 nodelay(1);
48}
49
50isocket* isocket::accept() throw(merror_t)
51{
52 sockaddr_in tsa; socklen_t tsalen;
53 memset(&tsa,0,tsalen=sizeof(tsa));
54 int tfd=::accept(fd,(sockaddr*)&tsa,&tsalen);
55 if(tfd>0) return new isocket(tfd,tsa);
56 if(errno!=EAGAIN) THROW("isocket: could not accept");
57 return 0;
58}
diff --git a/src/net/isocket.h b/src/net/isocket.h
new file mode 100644
index 0000000..5ca1ec3
--- /dev/null
+++ b/src/net/isocket.h
@@ -0,0 +1,68 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifndef ISOCKETH
21#define ISOCKETH
22
23#include <mt/mread.h>
24#include <mt/mstring.h>
25#include <sys/socket.h>
26#include <arpa/inet.h>
27#include <netinet/in.h>
28#include <netinet/tcp.h>
29
30class isocket : public pipe_stream {
31public:
32 isocket(const in_addr& ia,int port,int backlog);
33 isocket(int f,const sockaddr_in& ia);
34 ~isocket() { close(); }
35
36 void close() { if(fd>=0) { ::close(fd); fd=-1; }}
37
38 int getfd() const { return fd; }
39 int family() const { return sa.sin_family; }
40 int port() const { return ntohs(sa.sin_port); }
41 in_addr address() const { return sa.sin_addr; }
42
43 void reuse(int ok) { set(SOL_SOCKET,SO_REUSEADDR,ok); }
44 void nodelay(int ok) { set(IPPROTO_TCP,TCP_NODELAY,ok); }
45 void keepalive(int ok) { set(SOL_SOCKET,SO_KEEPALIVE,ok); }
46 void sendbufsize(int s) { set(SOL_SOCKET,SO_SNDBUF,s); }
47 void recvbufsize(int s) { set(SOL_SOCKET,SO_RCVBUF,s); }
48
49 isocket* accept() throw(merror_t);
50
51 int test() { return rd.poll(); }
52 int getsome(char* s,int n) { return rd.read(s,n); }
53 int gethead(char* s,int n) { return rd.readpara(s,n); }
54 int getbody(char* s,int n) { return rd.readx(s,n); }
55
56protected:
57 void setflag(int f) { fcntl(fd,F_SETFL,f); }
58 int getflag() const { return fcntl(fd,F_GETFL,0); }
59 void set(int lev,int opt,int ok) throw(merror_t) {
60 if(setsockopt(fd,lev,opt,(char*)&ok,sizeof(ok))<0)
61 THROW("isocket: Could not set option");
62 }
63private:
64 sockaddr_in sa;
65 mread rd;
66};
67
68#endif
diff --git a/src/net/redirect.cc b/src/net/redirect.cc
new file mode 100644
index 0000000..7e07e7c
--- /dev/null
+++ b/src/net/redirect.cc
@@ -0,0 +1,185 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <net/isocket.h>
21#include <mail/res.h>
22#include <http/http.h>
23#include <mt/lookup.h>
24#include <mt/lock.h>
25#include <sys/utsname.h>
26#include <signal.h>
27
28static fp_stream merr(stderr);
29static IPnode NODE;
30static int PORT;
31static mstring URL,PATH,SERVER,URL1,URL2;
32static int volatile RUNNING;
33
34const mstring REDIRECT="/tmp/redirect.";
35const int BACKLOG=4;
36const int SNDBUFSIZE=16384;
37const int RCVBUFSIZE=16384;
38const int MAXHEAD=16384;
39const int SAFEZONE=4096;
40
41static void BreakURL()
42{
43 static const mstring pre="//";
44 int p=URL.find(pre);
45 if(p>=0) {
46 p+=pre.size();
47 int q=p+URL.right(p).find('/');
48 if(q>=p) {
49 URL1=URL.left(q);
50 URL2=URL.right(q);
51 }
52 else {
53 URL1=URL;
54 URL2.clear();
55 }
56 }
57 else throw(0);
58}
59
60static mstring Combine(const sref& uri)
61{
62 const int ncvt=3;
63 static const mstring cvt[ncvt]={"/BODY","/en","/sv"};
64 mstring d=uri;
65 mstring s=URL1;
66 for(int i=0;i<ncvt;i++) {
67 int p=d.find(cvt[i]);
68 if(p>=0) {
69 d.erase(p,cvt[i].size());
70 s+=cvt[i];
71 }
72 }
73 s+=URL2;
74 s+=d;
75 return s;
76}
77
78static int Handle(isocket& sock)
79{
80 mstring buffer(MAXHEAD+SAFEZONE);
81 int nhead=sock.gethead(buffer.data(),MAXHEAD);
82 if(nhead<=0) return 0;
83 httpReq req(sref(buffer.data(),nhead));
84 httpResp resp;
85 resp.status=HTTP_301;
86 //resp.location=URL+req.uri;
87 resp.location=Combine(req.uri);
88 if(req.arg.nempty()) { resp.location.append(1,'?'); resp.location+=req.arg; }
89 resp.putHead(sock);
90 putend(sock);
91 sock.close();
92 return 1;
93}
94
95///////////////////////////////////////////////////////////////
96
97extern "C" {
98 static void onTERM(int sig) { RUNNING=0; }
99 typedef void (*disp_t)(int);
100}
101
102static void MainProc(isocket& sock)
103{
104 RUNNING=1;
105 while(RUNNING) {
106 int test=sock.test();
107 if(test>0) {
108 try {
109 isocket* s=sock.accept();
110 if(s) Handle(*s);
111 }
112 catch(const merror_t& e) {
113 merr<<"SOCKET: "<<e.desc<<"\n";
114 }
115 }
116 else if(test<0) RUNNING=0;
117 }
118}
119
120///////////////////////////////////////////////////////////////
121
122static void httpServer()
123{
124 isocket sock(NODE.addr,PORT,BACKLOG);
125 sock.keepalive(1);
126 sock.sendbufsize(SNDBUFSIZE);
127 sock.recvbufsize(RCVBUFSIZE);
128 sigignore(SIGPIPE);
129 disp_t onterm=signal(SIGTERM,onTERM);
130 disp_t onint=signal(SIGINT,onTERM);
131 MainProc(sock);
132 signal(SIGINT,onint);
133 signal(SIGTERM,onterm);
134}
135
136static void Daemon() try
137{
138 PROCLOCK(PATH);
139 merr<<"redirect: "<<SERVER<<" -> "<<URL<<" started\n";
140 httpServer();
141}
142catch(const merror_t& e) {
143 if(First(e.desc)!=sref("proclock:")) merr<<e.desc<<"\n";
144}
145catch(...) {
146 merr<<"FATAL\n";
147}
148
149main(int argc,char* argv[]) try
150{
151 if(argc<3) {
152 merr<<"Usage: "<<argv[0]<<" [host:]<port> <url> [-1|0|1]\n";
153 return -1;
154 }
155 sref s(argv[1]);
156 mstring host=s.left_last(':');
157 mstring sport=s.past_last(':');
158 if(sport.empty()) {
159 sport=host;
160 host.clear();
161 }
162 PORT=atoi(sport);
163 URL=argv[2];
164 if(URL.back()=='/') URL=URL.popb();
165 BreakURL();
166 if(host.empty()) {
167 struct utsname u; uname(&u);
168 host=u.nodename;
169 }
170 Lookup(NODE,host);
171 SERVER=NODE.name; SERVER.append(1,'-'); SERVER+=itoa(PORT);
172 PATH=REDIRECT; PATH+=SERVER;
173 int cmd=argc>3?atoi(argv[3]):0;
174 if(cmd) ProcTerminate(PATH);
175 if(cmd>=0) { if(fork()==0) Daemon(); }
176 return 0;
177}
178catch(const merror_t& e) {
179 merr<<"ERROR: ["<<e.desc<<"]\n";
180 return -1;
181}
182catch(...) {
183 merr<<"ERROR: [FATAL]\n";
184 return -1;
185}
diff --git a/src/net/route80.cc b/src/net/route80.cc
new file mode 100644
index 0000000..e883aba
--- /dev/null
+++ b/src/net/route80.cc
@@ -0,0 +1,64 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <net/isocket.h>
21#include <mt/lookup.h>
22#include <sys/utsname.h>
23
24static fp_stream merr(stderr);
25static IPnode NODE;
26static mstring PATH;
27static int PORT;
28
29const int BACKLOG=4;
30const int SNDBUFSIZE=16384;
31const int RCVBUFSIZE=16384;
32
33///////////////////////////////////////////////////////////////
34
35static void MainProc(isocket& sock)
36{
37 int fd=dup2(sock.fd,0);
38 if(fd!=0) { merr<<"Not right\n"; return; }
39 execl("htcd","htcd",PATH.c_str(),"-1",0);
40}
41
42///////////////////////////////////////////////////////////////
43
44static void httpServer()
45{
46 isocket sock(NODE.addr,PORT,BACKLOG);
47 sock.keepalive(1);
48 sock.sendbufsize(SNDBUFSIZE);
49 sock.recvbufsize(RCVBUFSIZE);
50 MainProc(sock);
51}
52
53main(int argc,char* argv[])
54{
55 if(argc<3) { merr<<"Usage: "<<argv[0]<<" <path> <port>\n"; return -1; }
56 PATH=argv[1]; if(PATH.back()=='/') PATH=PATH.popb();
57 PORT=atoi(argv[2]);
58 struct utsname u; uname(&u);
59 Lookup(NODE,sref(u.nodename));
60 httpServer();
61 return 0;
62}
63
64
diff --git a/src/net/server.cc b/src/net/server.cc
new file mode 100644
index 0000000..6996b20
--- /dev/null
+++ b/src/net/server.cc
@@ -0,0 +1,75 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <net/server.h>
21
22const mstring SERVURI="/htc/server.htc";
23
24htcServ::htcServ(const sref& path) : htcd(path),user(htcd.toks)
25{
26 Setup(user,htcd);
27 LoadBuffer(server,path+SERVURI);
28}
29
30///////////////////////////////////////////////////////
31
32static void Log(fp_stream& tlog,htcd_req& R,const sref& status)
33{
34 MLOCK(R.htcd()->mutex);
35 tlog<<"["<<time(0)<<"]["<<R.tcp->node.ip<<"]["
36 <<R.tcp->node.name<<":"<<R.tcp->port<<"]["
37 <<R.group<<":"<<R.user.uid()<<"]["
38 <<First(status)<<"]["<<R.req->method<<"]["
39 <<R.req->uri<<"]["<<R.req->arg<<"]\n";
40 tlog.flush();
41}
42
43///////////////////////////////////////////////////////
44
45int SendStatus(isocket& out,htcd_req& R,int keep,const sref& status,const sref& msg)
46{
47 R.resp.status=status;
48 if(atof(R.req->version.past_first(http_ver))<http_major) R.resp.version=HTTP_V10;
49 if(keep) R.resp.connect=keep_tag;
50 if(R.resp.cont_enc.nempty()||
51 R.resp.trans_enc.nempty()||
52 R.resp.status==HTTP_100||
53 R.resp.status==HTTP_204||
54 R.resp.status==HTTP_304||
55 eqn(R.req->method,HTTP_HEAD)) {
56 R.resp.cont_type.clear();
57 R.resp.cont_length.clear();
58 }
59 else {
60 if(R.resp.cont_type.empty()) R.resp.cont_type=http_mime_default;
61 R.resp.cont_length=itoa(msg.size());
62 }
63 Log(R.htcd()->logger,R,status);
64 R.resp.putHead(out);
65 putend(out);
66 out<<msg;
67#if 0
68 static fp_stream merr(stderr);
69 merr<<"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n";
70 R.resp.putHead(merr);
71 putend(merr);
72 merr<<"=================================\n";
73#endif
74 return out.hup?0:keep;
75}
diff --git a/src/net/server.h b/src/net/server.h
new file mode 100644
index 0000000..65f884c
--- /dev/null
+++ b/src/net/server.h
@@ -0,0 +1,46 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifndef SERVERH
21#define SERVERH
22
23#include <serv/htcd.h>
24#include <hdb/buffer.h>
25#include <net/isocket.h>
26#include <mt/lock.h>
27#include <signal.h>
28
29const mstring http_ver="HTTP/";
30const double http_minor=1.0,http_major=1.1;
31
32const mstring keep_tag="Keep-Alive";
33const mstring close_tag="Close";
34const mstring expect_continue_tag="100-continue";
35
36struct htcServ {
37 HTCd htcd;
38 tokmap user;
39 mstring server;
40 htcServ(const sref& path);
41};
42
43int SendStatus(isocket& out,htcd_req& R,int keep,
44 const sref& status,const sref& msg=ms_empty);
45
46#endif
diff --git a/src/net/test.cc b/src/net/test.cc
new file mode 100644
index 0000000..c0e3b41
--- /dev/null
+++ b/src/net/test.cc
@@ -0,0 +1,44 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <mt/mlock.h>
21#include <iostream>
22using namespace std;
23
24static mutex_t mutex;
25static mtcond_t cond;
26
27static void* thread(void* a)
28{
29 cerr<<"thread "<<a<<endl;
30 MSUSPEND(mutex,cond);
31 return 0;
32}
33
34main()
35{
36 pthread_t tid;
37 pthread_create(&tid,0,thread,(void*)2);
38 cerr<<"main thread"<<endl;
39 sleep(2);
40 MCONTINUE(cond);
41 pthread_join(tid,0);
42 cerr<<"afer join"<<endl;
43 return 0;
44}
diff --git a/src/net/thrserv.cc b/src/net/thrserv.cc
new file mode 100644
index 0000000..0d91d12
--- /dev/null
+++ b/src/net/thrserv.cc
@@ -0,0 +1,255 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <net/thrserv.h>
21#include <errno.h>
22
23const mstring cron_tag="\\run.cron";
24const mstring FATAL="FATAL ERROR";
25const mstring UNKNOWN="UNKNOWN";
26const mstring REJECTED="REJECTED";
27
28const int MAXHEAD=16384;
29const int MAXBODY=2<<21;
30const int MAXURI=4096;
31const int MAXARG=4096;
32const int SAFEZONE=4096;
33
34///////////////////////////////////////////////////////////////
35
36thrServ::thrServ(htcServ& server):
37 pmutex(MUTEX_INIT),
38 pcond(MTCOND_INIT),
39 keepalive(0),running(0),termok(0),
40 first(time(0)),last(time(0)),
41 serv(&server),
42 sock(0),
43 user(server.user,server.htcd.docroot)
44{
45}
46
47thrServ::~thrServ()
48{
49 delete sock;
50}
51
52void thrServ::reset(isocket* s,int keep)
53{
54 keepalive=keep;
55 running=1;
56 termok=0;
57 first=time(0);
58 last=time(0);
59 sock=s;
60 while(!tid);
61 if(MCONTINUE(pcond)) throw((int)0);
62}
63
64void thrServ::Log(const sref& msg)
65{
66 MLOCK(serv->htcd.mutex);
67 if(sock) serv->htcd.errlog<<"["<<time(0)<<"]["<<tid<<"]["
68 <<inet_ntoa(sock->address())<<":"<<sock->port()<<"]["
69 <<msg<<"]\n";
70 else serv->htcd.errlog<<"["<<time(0)<<"]["<<tid<<"]["<<msg<<"]\n";
71 serv->htcd.errlog.flush();
72}
73
74void thrServ::enter()
75{
76 tid=pthread_self();
77 MSUSPEND(pmutex,pcond)
78 while(serv->htcd.running&&!termok) {
79 session();
80 delete sock;
81 sock=0;
82 if(serv->htcd.running&&!termok) {
83 MSUSPEND(pmutex,pcond)
84 }
85 }
86}
87
88void thrServ::session() try
89{
90 int keep=1;
91 while(sock&&keep&&running) {
92 int test=sock->test();
93 if(test>0) { last=time(0); keep=handle(); }
94 else if(test<0) keep=0;
95 }
96}
97catch(const merror_t& e) {
98 Log(e.desc);
99}
100catch(...) {
101 Log(FATAL);
102}
103
104///////////////////////////////////////////////////////////////
105
106thrCron::thrCron(htcServ& server):
107 tid(0),running(0),serv(&server),user(server.user,server.htcd.docroot)
108{
109}
110
111void thrCron::Log(const sref& msg)
112{
113 MLOCK(serv->htcd.mutex);
114 serv->htcd.errlog<<"["<<time(0)<<"][CRON]["<<msg<<"]\n";
115 serv->htcd.errlog.flush();
116}
117
118void thrCron::enter() try
119{
120 tid=pthread_self();
121 tcpReq tcp; tcp.port=0;
122 httpReq req;
123 mstream devnull;
124 htcd_req R(serv->htcd,user.toks,devnull,tcp,req);
125 Env env(serv->htcd.ops,R,XSYSTEM);
126 env.req->running=&running;
127 running=1;
128 mstream m;
129 env.parse(m,cron_tag);
130}
131catch(const merror_t& e) {
132 Log(e.desc);
133}
134catch(...) {
135 Log(FATAL);
136}
137
138
139///////////////////////////////////////////////////////////////
140
141int thrServ::handle()
142{
143 tcpReq tcp;
144 tcp.port=sock->port();
145 if(!Lookup(tcp.node,sock->address())) {
146 Log(REJECTED);
147 return 0;
148 }
149
150 //////////////////////////////////////////////////////////////////
151
152 mstring buffer(MAXHEAD+MAXBODY+SAFEZONE);
153 int nhead=sock->gethead(buffer.data(),MAXHEAD);
154 if(nhead==0) return 0;
155 else if(nhead<0) return 0;
156
157 sref message(buffer.data(),nhead);
158
159#if 0
160 static fp_stream merr(stderr);
161 merr<<"QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ\n";
162 merr<<message<<"\n";
163 merr<<"=====================================\n";
164#endif
165
166 httpReq req(message);
167
168 //////////////////////////////////////////////////////////////////
169
170 int keep=keepalive;
171 if(!eqn(req.connect,keep_tag)) keep=0;
172
173 mswrite cache;
174 htcd_req R(serv->htcd,user.toks,cache,tcp,req);
175
176 //////////////////////////////////////////////////////////////////
177
178 if(nhead>=MAXHEAD) return SendStatus(*sock,R,keep,HTTP_413);
179
180 if(eqn(req.method,HTTP_TRACE)) {
181 R.resp.cont_type="message/http";
182 return SendStatus(*sock,R,keep,HTTP_200,buffer.left(nhead));
183 }
184
185 if(req.expect.nempty()) {
186 if(eqn(req.expect,expect_continue_tag)) SendStatus(*sock,R,keep,HTTP_100);
187 else return SendStatus(*sock,R,keep,HTTP_417);
188 }
189
190 if(req.trans_enc.nempty()||req.cont_enc.nempty()) return SendStatus(*sock,R,0,HTTP_501);
191
192 //////////////////////////////////////////////////////////////////
193
194 int ilength=atoi(req.cont_length);
195 if(ilength>MAXBODY) return SendStatus(*sock,R,0,HTTP_413);
196 else if(ilength>0) {
197 int nbody=sock->getbody(buffer.data()+nhead,ilength);
198 if(nbody<0) return 0;
199 else {
200 sref sbody(buffer.data()+nhead,nbody);
201#if 0
202 static fp_stream merr(stderr);
203 merr<<"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP\n";
204 merr<<sbody<<"\n";
205 merr<<"=====================================\n";
206#endif
207 R.AddBody(sbody);
208 if(req.body.size()!=ilength) return 0;
209 }
210 }
211
212 //////////////////////////////////////////////////////////////////
213
214 if(eqn(req.method,HTTP_OPTIONS)) {
215 R.resp.allow="HEAD GET PUT POST DELETE";
216 return SendStatus(*sock,R,keep,HTTP_200);
217 }
218
219 //////////////////////////////////////////////////////////////////
220
221 if(req.cont_length.empty()&&(eqn(req.method,HTTP_PUT)||eqn(req.method,HTTP_POST)))
222 return SendStatus(*sock,R,0,HTTP_411);
223
224 if(eqn(req.method,HTTP_HEAD)||
225 eqn(req.method,HTTP_GET)||
226 eqn(req.method,HTTP_PUT)||
227 eqn(req.method,HTTP_DELETE)||
228 eqn(req.method,HTTP_POST)) {
229 R.resp.cont_type=mime_texthtml;
230 R.resp.cont_type_charset=mime_default;
231 try {
232 Env env(serv->htcd.ops,R,XSYSTEM);
233 env.req->running=&running;
234 mstream m;
235 env.parse(m,serv->server);
236 if(!env.req->is_running()) THROW("htc: "<<req.uri<<" ended prematurely; reload");
237 }
238 catch(const merror_t& e) {
239 Log(e.desc);
240 return SendStatus(*sock,R,0,HTTP_503,e.desc);
241 }
242 }
243 else return SendStatus(*sock,R,keep,HTTP_501);
244
245 if(!keepalive) keep=0;
246 if(req.if_mod.nempty()&&R.resp.lastmod.nempty()) {
247 time_t since=cvtTime(req.if_mod),lst=cvtTime(R.resp.lastmod);
248 if(lst<=since) return SendStatus(*sock,R,keep,HTTP_304);
249 }
250
251 mstring status=R.resp.status;
252 if(eqn(req.method,HTTP_HEAD)) return SendStatus(*sock,R,keep,status);
253 else return SendStatus(*sock,R,keep,status,cache.str());
254
255}
diff --git a/src/net/thrserv.h b/src/net/thrserv.h
new file mode 100644
index 0000000..09307f6
--- /dev/null
+++ b/src/net/thrserv.h
@@ -0,0 +1,79 @@
1/*************************************************************************
2 *
3 * HTCd - Copyright (C) 1998-2006 Henrik Rydberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifndef THRSERVH
21#define THRSERVH
22
23#include <net/server.h>
24#include <mt/lookup.h>
25#include <mt/mlock.h>
26
27////////////////////////////////////////////////////////
28//
29// MT - safe
30// Note that mutexes aren't needed here, since control
31// is flowing from main to child, with possible child
32// override in local variables.
33
34struct thrServ {
35 pthread_t ptid;
36 mutex_t pmutex;
37 mtcond_t pcond;
38 volatile int tid,keepalive,running,termok;
39 time_t first,last;
40 htcServ* serv;
41 isocket* sock;
42 htcd_user user;
43
44 thrServ(htcServ& server);
45 ~thrServ();
46
47 void Log(const sref& msg);
48 void reset(isocket* s,int keep);
49
50 int vacant() const { return sock==0; }
51 int shutdown() { keepalive=0; return sock==0; }
52 void disconnect() { keepalive=0; running=0; }
53 void term() {
54 keepalive=0;
55 running=0;
56 termok=1;
57 MCONTINUE(pcond);
58 }
59
60 void enter();
61 void session();
62 int handle();
63};
64
65////////////////////////////////////////////////////////
66
67struct thrCron {
68 pthread_t ptid;
69 volatile int tid,running;
70 htcServ* serv;
71 htcd_user user;
72
73 thrCron(htcServ& server);
74
75 void Log(const sref& msg);
76 void enter();
77};
78
79#endif