main 主函数
int main(int argc, char** argv)
{
int i;
char *zPermUser = 0;
const char *zPort = 0;
int useChrootJail = 1;
struct passwd *pwd = NULL;
gettimeofday(&beginTime, 0);
while( argc>1 && argv[1][0] == '-')
{
char *z = argv[1];
char *zArg = argc>=3 ? argv[2] : "0";
if(strcmp(z[0],"-") == 0 && strcmp(z[1],"-"))
z++;
if(strcmp(z, "-user")==0)
{
zPermUser = zArg;
}
else if(strcmp(z,"-root")==0)
{
zRoot = zArg;
}
else if (strcmp(z,"-logfile") == 0)
{
zLogFile = zArg;
}
else if(strcmp(z,"-max-age") == 0)
{
mxAge = zArg;
}
else if(strcmp(z,"-max-cpu") == 0)
{
maxCpu = atoi(zArg);
}
else if(strcmp(z,"-https") == 0)
{
useHttps = atoi(zArg);
zHttp = useHttps ? "https" : "http";
if( useHttps )
{
zRemoteAddr = getenv("REMOTE_HOST");
}
}
else if(strcmp(z,"-port") == 0)
{
zPort = zArg;
standalone =1;
}
else if( strcmp(z, "-family")==0 )
{
if( strcmp(zArg, "ipv4")==0 )
{
ipv4Only = 1;
}
else if( strcmp(zArg, "ipv6")==0 )
{
ipv6Only = 1;
}
else
{
Malfunction(500, "unknown IP protocol: [%s]\n", zArg);
}
}
else if( strcmp(z, "-jail")==0 )
{
if( atoi(zArg)==0 )
{
useChrootJail = 0;
}
}
else if( strcmp(z, "-debug")==0 )
{
if( atoi(zArg) )
{
useTimeout = 0;
}
}
else if( strcmp(z, "-input")==0 )
{
if( freopen(zArg, "rb", stdin)==0 || stdin==0 )
{
Malfunction(501, "cannot open --input file \"%s\"\n", zArg);
}
}
else if( strcmp(z, "-datetest")==0 )
{
TestParseRfc822Date();
exit(0);
}
else
{
Malfunction(510, "unknown argument: [%s]\n", z);
}
argv += 2;
argc -= 2;
}
if(zRoot == 0)
{
if(standalone)
{
zRoot = ".";
}
else
{
Malfunction(520, "no --root specified");
}
}
if( chdir(zRoot)!=0 )
{
Malfunction(530,"cannot change to directory [%s]", zRoot);
}
if( zPermUser )
{
pwd = getpwnam(zPermUser);
}
if( zPermUser && useChrootJail && getuid()==0 )
{
if( chroot(".")<0 )
{
Malfunction(540,
"unable to create chroot jail");
}
else
{
zRoot = "";
}
}
if( zPort && http_server(zPort, 0) )
{
Malfunction(550, "failed to start server");
}
#ifdef RLIMIT_CPU
if( maxCpu>0 ){
struct rlimit rlim;
rlim.rlim_cur = maxCpu;
rlim.rlim_max = maxCpu;
setrlimit(RLIMIT_CPU, &rlim);
}
#endif
if (zPermUser)
{
if (pwd)
{
if (setgid(pwd->pw_gid))
{
Malfunction(560, "cannot set group-id to %d", pwd->pw_gid);
}
if (setuid(pwd->pw_uid))
{
Malfunction(570, "cannot set user-id to %d", pwd->pw_uid);
}
}
else
{
Malfunction(580, "no such user [%s]", zPermUser);
}
}
if (getuid() == 0)
{
Malfunction(590, "cannot run as root");
}
if (zRemoteAddr == 0)
{
address remoteAddr;
unsigned int size = sizeof(remoteAddr);
char zHost[NI_MAXHOST];
if (getpeername(0, &remoteAddr.sa, &size) >= 0)
{
getnameinfo(&remoteAddr.sa, size, zHost, sizeof(zHost), 0, 0, NI_NUMERICHOST);
zRemoteAddr = StrDup(zHost);
}
}
if (zRemoteAddr != 0 && strncmp(zRemoteAddr, "::ffff:", 7) == 0 && strchr(zRemoteAddr + 7, ':') == 0 && strchr(zRemoteAddr + 7, '.') != 0)
{
zRemoteAddr += 7;
}
for (i = 0; i < 100; i++)
{
ProcessOneRequest(0);
}
ProcessOneRequest(1);
exit(0);
return 0;
}
http_server函数
int http_server(const char *zPort, int localOnly)
{
int listener[20];
int connection;
fd_set readfds;
address inaddr;
socklen_t lenaddr;
int child;
int nchildren = 0;
struct timeval delay;
int opt = -1;
struct addrinfo sHints;
struct addrinfo *pAddrs, *p;
int rc;
int i, n;
int maxFd = -1;
memset(&sHints, 0, sizeof(sHints));
if(ipv4Only)
{
sHints.ai_family = PF_INET;
}
else if(ipv6Only)
{
sHints.ai_family = PF_INET6;
}
else
{
sHints.ai_family = PF_UNSPEC;
}
sHints.ai_socktype = SOCK_STREAM;
sHints.ai_flags = AI_PASSIVE;
sHints.ai_protocol = IPPROTO_IP;
rc = getaddrinfo(localOnly ? "localhost": 0,zPort, &sHints, &pAddrs);
if(rc)
{
fprintf(stderr, "could not get addr info: %s", rc!=EAI_SYSTEM ? gai_strerror(rc) : strerror(errno));
return 1;
}
for(n=0, p=pAddrs; n<(int)(sizeof(listener)/sizeof(listener[0])) && p != 0; p=p->ai_next)
{
listener[n] = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if(listener[n] >= 0)
{
setsockopt(listener[n], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
#if defined(IPV6_V6ONLY)
if( p->ai_family==AF_INET6 )
{
int v6only = 1;
setsockopt(listener[n], IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only));
}
#endif
if(bind(listener[n], p->ai_addr, p->ai_addrlen) < 0)
{
printf("bind failed: %s\n", strerror(errno));
close(listener[n]);
continue;
}
if( listen(listener[n], 20) < 0 )
{
printf("listen() failed: %s\n", strerror(errno));
close(listener[n]);
continue;
}
n++;
}
}
if(n == 0)
{
fprintf(stderr, "cannot open any sockets\n");
return 1;
}
while (1)
{
if(nchildren > MAX_PARALLEL)
{
sleep(nchildren - MAX_PARALLEL);
}
delay.tv_sec = 60;
delay.tv_usec = 0;
FD_ZERO(&readfds);
for(i=0; i<n; i++)
{
assert(listener[0] >= 0 );
FD_SET(listener[i], &readfds);
if(listener[i] > maxFd)
maxFd = listener[i];
}
select(maxFd+1, &readfds, 0, 0, &delay);
for(i=0; i<n; i++)
{
if(FD_ISSET(listener[i], &readfds))
{
lenaddr = sizeof(inaddr);
connection = accept(listener[i], &inaddr.sa, &lenaddr);
if(connection >= 0)
{
child = fork();
if(child != 0)
{
if(child>0)
nchildren++;
close(connection);
}
else
{
int nErr =0, fd;
close(0);
fd = dup(connection);
if(fd != 0)
nErr++;
close(1);
fd = dup(connection);
if(fd != 1)
nErr++;
close(connection);
return nErr;
}
}
}
while( (child = waitpid(0, 0, WNOHANG))>0 )
{
nchildren--;
}
}
}
exit(1);
}
总结
- Althttpd的主要三个函数为main函数、http_server函数和ProcessOneRequest函数。
- http_server函数负责监听和fork子进程,子进程产生后退出http_server函数并调用ProcessOneRequest函数处理请求,处理请求中我们忽略掉cgi网关部分,就会发现其实是HTTP的组包收发。
- Althttpd的设计思想别出心裁,对于加深linux的学习很有帮助。