您当前的位置: 首页 >  http

phymat.nico

暂无认证

  • 1浏览

    0关注

    1967博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

thttpd源码分析

phymat.nico 发布时间:2017-12-18 22:26:52 ,浏览量:1

thttpd源码分析

最近多了个看源码的嗜好

  main函数已经分析好了,找时间分离好代码,待续...

thttpd Web Server模块
thttpd Web Server#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

typedef union
{
	struct sockaddr sa;
	struct sockaddr_in sa_in;
#ifdef USE_IPV6
	struct sockaddr_in6 sa_in6;
	struct sockaddr_storage sa_stor;
#endif
}httpd_sockaddr;

typedef struct
{
	char* server_hostname;
	char* binding_hostname;
	unsigned short port;
	int listen4_fd;
	int listen6_fd;
}httpd_server;

#define SPARE_FDS 10

#define FDW_READ 0
#define FDW_WRITE 1

#ifndef MIN
	#define MIN(a,b) ((a)= fdw->nfiles )
		{
			//syslog( LOG_ERR, "too many fds in select_add_fd!" );
			return;
		}
		select_fds[nselect_fds] = fd;
		switch ( rw )
		{
		case FDW_READ: FD_SET( fd, &master_rfdset ); break;
		case FDW_WRITE: FD_SET( fd, &master_wfdset ); break;
		default: break;
		}
		if ( fd > maxfd )
		maxfd = fd;
		select_fdidx[fd] = nselect_fds;
		++nselect_fds;
	}

#else
	#ifdef HAVE_POLL
	#endif
#endif

int FdWatcher::fdwatch_get_nfiles()
{
	int i;
	//FdWatcher* fd=fdw;
	
	//返回一个进程能打开的最大文件数
	fd->nfiles=getdtablesize();
	
	//如果可以使用rlimit,则使用rlimit获取更精确的limit
	struct rlimit rl;
	if( getrlimit(RLIMIT_NOFILE,&rl)==0 )
	{
		if( rl.rlim_max== RLIM_INFINITY)
			rl.rlim_cur=8192;
		else if (rl.rlim_max>rl.rlim_cur)
			rl.rlim_cur=rl.rlim_max;
		//尝试设置limit为最大,如果不行就放弃
		setrlimit(RLIMIT_NOFILE,&rl);
		
		fd->nfiles=rl.rlim_cur;
	}
	
#if defined(HAVE_SELECT) && !( defined(HAVE_POLL) || defined(HAVE_DEVPOLL) || defined(HAVE_KQUEUE) )
//如果使用select,则nfile不能超过FD_SETSIZE
	fd->nfiles= MIN(fd->nfiles,FD_SETSIZE);
#endif

	//然后初始化和fdwatch相关的数据成员
	
	fd->nwatches=0;
	fd->fd_rw=(int*)malloc(sizeof(int)*fd->nfiles);
	fd->fd_data=(void**)malloc(sizeof(void*)*fd->nfiles);
	if(fd->fd_rw==(int*)0 || fd->fd_data==(void**)0 )
		return -1;
	for( i=0;infiles;++i)
		fd->fd_rw[i]=-1;
	
}

void FdWatcher::fdwatch_add_fd(int fd, void* client_data,int rw)
{
	if(fd=nfiles || fd_rw[fd]!=-1 )
	{
	//error
	return;
	}
	//根据预定义的处理方式选择不同的ADD_FD方法
	ADD_FD(fd,rw);
	//使用fd_rw和fd_data两个bitmap数组,对应slot上存放对应fd的rw标志和cd
	fd_rw[fd]=rw;
	fd_data[fd]=client_data;
}
/** fdwatcher **/
#endif


/** tool function **/
static void lookup_hostname( httpd_sockaddr* sa4P, size_t sa4_len, int* gotv4P, httpd_sockaddr* sa6P, size_t sa6_len, int* gotv6P )
{
#ifdef USE_IPV6
//...
#else //IPV4
	//hostent结构体,gethostbyname返回值类型,数据成员包括(主机规范名,主机别名,主机ip地址类型,ip地址长度,网络字节序的主机ip地址)
	struct hostent *he;
	//表示不使用v6版本
	*gotv6P=0;
	
	(void)memset(sa4P,0,sa4_len);
	sa4P->sa.sa_family=AF_INET;
	//没有指定监听hostname,则绑定到所有接口
	if( hostname==(char*)0 )
		sa4P->sa_in.sin_addr.s_addr=htonl(INADDR_ANY);
	else
	{
		//如果指定了hostname,那要通过gethostbyname获取ip等信息。
		sa4P->sa_in.sin_addr.s_addr=inet_addr(hostname);
		if( (int)sa4P->sa_in.sin_addr.s_addr==-1)
		{
			he=gethostbyname(hostname);
			if(he == (struct hostent*)0 )
			{
			//error
			exit(1);
			}
			if( he->h_addrtype!=AF_INET)
			{
			//error
			exit(1);
			}
			(void) memmove(&sa4P->sa_in.sin_addr.s_addr , he->h_addr, he->h_length);
		}
	}
	sa4P->sa_in.sin_port=htons(port);
	*gotv4P=1;
#endif	
}
long tmr_mstimeout(struct timeval* nowP)
{
	return 0;
}
/** tool function **/


/** httpd_initialize **/
#ifdef SERVER_NAME_LIST
static char*
hostname_map( char* hostname )
    {
    int len, n;
    static char* list[] = { SERVER_NAME_LIST };

    len = strlen( hostname );
    for ( n = sizeof(list) / sizeof(*list) - 1; n >= 0; --n )
	if ( strncasecmp( hostname, list[n], len ) == 0 )
	    if ( list[n][len] == '/' )  /* check in case of a substring match */
		return &list[n][len + 1];
    return (char*) 0;
    }
#endif /* SERVER_NAME_LIST */
static int initialize_listen_socket(httpd_sockaddr* sap)
{}
static void free_httpd_server(httpd_server* hs)
{}
httpd_server* httpd_initialize(char *hostname,httpd_sockaddr* sa4p, httpd_sockaddr *sa6p,unsigned short port)
{
	httpd_server *hs=(httpd_server*)malloc(sizeof(httpd_server));
	static char ghnbuf[256];
	
	if(hs==(httpd_server*)0)
	{
		printf("out of memory for allocating httpd_server \n");
		return (httpd_server*)0;
	}
	
	//在此之前有调用gethostbyname等操作
	if(hostname!=(char*)0)
	{
		//设置hs的bindinghostname和serverhostname
		hs->binding_hostname=strdup(hostname);
		if( hs->binding_hostname==(char*)0 )
		{
			printf("out of memory copying hostname\n");
			return (httpd_server*)0;
		}
		hs->server_hostname=hs->binding_hostname;
	}
	else
	{
		hs->binding_hostname=(char*)0;
		hs->server_hostname=(char*)0;
		//得到主机名
		if(gethostname(ghnbuf,sizeof(ghnbuf))server_hostname=hostname_map(ghnbuf);
		#endif
	
		if ( hs->server_hostname==(char*)0)
		{
			#ifdef SERVER_NAME
				hs->server_hostname=SERVER_NAME;
			#else
				if(ghnbuf[0]!='\0')
					hs->server_hostname=ghnbuf;
			#endif
		}
	}
	
	hs->port=port;
	//initialize_listen_socket,就是socket bind listen
	if( sa6p == (httpd_sockaddr*)0)
		hs->listen6_fd=-1;
	else
		hs->listen6_fd=initialize_listen_socket(sa6p);
	if( sa4p == (httpd_sockaddr*)0)
		hs->listen4_fd=-1;
	else
		hs->listen4_fd=initialize_listen_socket(sa4p);
		
	if(hs->listen4_fd==-1 && hs->listen6_fd==-1)
	{
		free_httpd_server(hs);
		return (httpd_server*)0;
	}
}
/** httpd_initialize **/


int main()
{
	hostname=0;
	port=51423;
	struct timeval tv;	
	
	
	//初始化sockaddr_in
	httpd_sockaddr sa4;
	httpd_sockaddr sa6;
	int gotv4, gotv6;
	lookup_hostname(&sa4,sizeof(sa4),&gotv4,&sa6,sizeof(sa6),&gotv6);
	
	
	//计算系统允许的fd数,初始化fdwatch,io复用模式相关的
	FdWatcher *fdw=FdWatcher::getFdWatcherInstance();
	max_connects=fdw->fdwatch_get_nfiles();
	if(max_connects < 0)
	{
		printf("fdwatch init failure\n");
		exit(1);
	}
	max_connects -= SPARE_FDS;

	
	//真正做network相关的。做hs初始化和socket,bind,listen
	hs=httpd_initialize(hostname,gotv4?&sa4:(httpd_sockaddr*)0,gotv6?&sa6:(httpd_sockaddr*)0,port);		
	
	if(hs != (httpd_server*)0)
	{
		if (hs->listen4_fd!=-1)
			//注册监听fd
			fdw->fdwatch_add_fd(hs->listen4_fd,(void*)0,FDW_READ);
		if (hs->listen6_fd!=-1)
			fdw->fdwatch_add_fd(hs->listen6_fd,(void*)0,FDW_READ);
	}
	
	int num_ready;
	(void) gettimeofday( &tv, (struct timezone*) 0 );
	while( (!terminate)||num_connects>0 )
	{
		num_ready=fdw->fdwatch(tmr_mstimeout(&tv));
		if(num_ready0
		//accept并加入listen set
		if ( hs != (httpd_server*) 0 && hs->listen6_fd != -1 && fdw->fdwatch_check_fd( hs->listen6_fd ) )
	    {
	//		if ( handle_newconnect( &tv, hs->listen6_fd ) )
				continue;
	    }
		if ( hs != (httpd_server*) 0 && hs->listen4_fd != -1 && fdw->fdwatch_check_fd( hs->listen4_fd ) )
	    {
	//		if ( handle_newconnect( &tv, hs->listen4_fd ) )
				continue;
	    }
		/*
		while
		*/
		
	//tmr_run(&tv);

/*	
		if( !terminate)
		{
			terminate=1;
			if (hs!=(httpd_server*)0)
			{
				if (hs->listen4_fd!=-1)
					fdw->fdwatch_del_fd(hs->listen4_fd);
				if (hs->listen6_fd!=-1)
					fdw->fdwatch_del_fd(hs->listen6_fd);
	//			httpd_unlisten(hs);
			}
		}
*/

	}//end while
	
	//shut_down();
	exit(0);
}

Chroot安全模块

chroot
复制代码
  1 /*
  2 chroot是一个系统调用,将程序的可见文件视图限制到当前目录及其下面的其他目录。这样其他远程user就无法访问初始目录外的文件。
  3 子进程也会有这样的属性,所以CGI文件也会有这样的效果。
  4 但是只有root才可以调用chroot,所以这意味程序只能由root启动,但是thttpd中最后root可以转换为其他user,也保证了这点。
  5 1.限制被CHROOT的使用者所能执行的程序
  6 2.防止使用者存取某些特定档案,如/etc/passwd。 
  7 3.防止入侵者/bin/rm -rf /。 
  8 4.提供Guest服务以及处罚恶意的使用者。 
  9 5.增进系统的安全。 
 10 文章:http://hi.baidu.com/alsrt/blog/item/de74f8389c36a32796ddd8be.html
 11 http://hi.baidu.com/alsrt/blog/item/04ccce43711280159213c6bd.html
 12 http://blog.csdn.net/hfw_1987/article/details/5362078
 13 */
 14 #include
 15 #include
 16 #include
 17 #include
 18 #include
 19 #include
 20 #include
 21 #include
 22 #include
 23 #include
 24 
 25 #define DEFAULT_USER "nobody"
 26 #ifndef MAXPATHLEN
 27 #define MAXPATHLEN 1024
 28 #endif
 29 
 30 void printCwd(char* cwd)
 31 {
 32     memset(cwd,0,sizeof(cwd));
 33     (void) getcwd(cwd,sizeof(cwd)-1);
 34     if(cwd[strlen(cwd)-1]!='/')
 35         (void) strcat(cwd,"/");    
 36     printf("%s\n",cwd);
 37 }
 38 int main()
 39 {
 40     char* user=(char *)"aga";    //DEFAULT_USER
 41     struct passwd* pwd;
 42     uid_t uid=32767;
 43     gid_t gid=32767;
 44     
 45     //如果是root权限,获取将要托管的user的uid和pid
 46     if( getuid()==0)
 47     {
 48         pwd=getpwnam(user);
 49         if(pwd==(struct passwd*)0)
 50         {
 51         //error
 52         printf("error pwd\n");
 53         exit(1);
 54         }
 55         uid=pwd->pw_uid;
 56         gid=pwd->pw_gid;
 57     }
 58     
 59     #ifdef USE_USER_DIR
 60     if( getuid()==0) 
 61     {
 62         if( chdir(pwd->pw_dir)            
关注
打赏
1659628745
查看更多评论
立即登录/注册

微信扫码登录

0.0549s