日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

thttpd源码分析

發(fā)布時間:2025/3/21 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 thttpd源码分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

thttpd源碼分析

最近多了個看源碼的嗜好

  main函數(shù)已經(jīng)分析好了,找時間分離好代碼,待續(xù)...

thttpd Web Server模塊 thttpd Web Server#include<stdio.h> #include<sys/socket.h> #include<stdlib.h> #include<arpa/inet.h> #include<string.h> #include<unistd.h> #include<time.h> #include<sys/time.h> #include<errno.h> #include<netdb.h> #include<sys/socket.h> #include<unistd.h> #include<sys/resource.h>typedef union {struct sockaddr sa;struct sockaddr_in sa_in; #ifdef USE_IPV6struct 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)<(b)?(a):(b)) #endifstatic int max_connects; static httpd_server* hs = (httpd_server*) 0; static int num_connects; static char* hostname; static int port; int terminate=0;#ifndef FDWATCHER #define FDWATCHER /** fdwatcher **/ //fdwatcher用于和多種IO復用方式協(xié)作完成IO復用,抽象出IO復用的使用接口 //IO復用使用宏定義加預編譯define形式實現(xiàn)多種IO復用形式的選擇 class FdWatcher { private:static FdWatcher *fd; public://可以監(jiān)聽的最大fd數(shù)int nfiles;//計數(shù)WATCH的調(diào)用次數(shù),輔助統(tǒng)計信息long nwatches;//使用定長數(shù)組,slot map,存放對應(yīng)fd的rw標志和data//read的fd和write的fd在IO復用中有不同的執(zhí)行方式,所以需要標志int* fd_rw;//client的數(shù)據(jù),可以是網(wǎng)絡(luò)數(shù)據(jù)或者輔助數(shù)據(jù)void** fd_data;//nreturned表示W(wǎng)ATCH得到的被激活fd數(shù)目//next_ridx表示W(wǎng)ATCH得到的被激活fd數(shù)組的下一個fd(static int* select_rfdidx;)int nreturned, next_ridx; private:FdWatcher(){nfiles=0;nwatches=0;fd_rw=0;fd_data=0;nreturned=next_ridx=0;} public:static FdWatcher *getFdWatcherInstance();int fdwatch_get_nfiles();void fdwatch_add_fd(int fd, void* client_data,int rw);void fdwatch_del_fd(int fd){}int fdwatch_check_fd(int fd){}int fdwatch(long timeout_msecs){} }; FdWatcher* FdWatcher::fd=NULL; FdWatcher* FdWatcher::getFdWatcherInstance() {if(fd==NULL)fd=new FdWatcher();return fd; } #define HAVE_SELECT #ifdef HAVE_SELECTstatic fd_set master_rfdset;static fd_set master_wfdset;static fd_set working_rfdset;static fd_set working_wfdset;static int* select_fds;static int* select_fdidx;static int* select_rfdidx;static int nselect_fds;static int maxfd;static int maxfd_changed;#define ADD_FD( fd, rw ) select_add_fd( fd, rw )static void select_add_fd( int fd, int rw ){FdWatcher *fdw=FdWatcher::getFdWatcherInstance();if ( nselect_fds >= 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 #endifint FdWatcher::fdwatch_get_nfiles() {int i;//FdWatcher* fd=fdw;//返回一個進程能打開的最大文件數(shù)fd->nfiles=getdtablesize();//如果可以使用rlimit,則使用rlimit獲取更精確的limitstruct 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;//嘗試設(shè)置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_SETSIZEfd->nfiles= MIN(fd->nfiles,FD_SETSIZE); #endif//然后初始化和fdwatch相關(guān)的數(shù)據(jù)成員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;i<fd->nfiles;++i)fd->fd_rw[i]=-1;}void FdWatcher::fdwatch_add_fd(int fd, void* client_data,int rw) {if(fd<0 || fd>=nfiles || fd_rw[fd]!=-1 ){//errorreturn;}//根據(jù)預定義的處理方式選擇不同的ADD_FD方法ADD_FD(fd,rw);//使用fd_rw和fd_data兩個bitmap數(shù)組,對應(yīng)slot上存放對應(yīng)fd的rw標志和cdfd_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結(jié)構(gòu)體,gethostbyname返回值類型,數(shù)據(jù)成員包括(主機規(guī)范名,主機別名,主機ip地址類型,ip地址長度,網(wǎng)絡(luò)字節(jié)序的主機ip地址)struct hostent *he;//表示不使用v6版本*gotv6P=0;(void)memset(sa4P,0,sa4_len);sa4P->sa.sa_family=AF_INET;//沒有指定監(jiān)聽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 ){//errorexit(1);}if( he->h_addrtype!=AF_INET){//errorexit(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;}//在此之前有調(diào)用gethostbyname等操作if(hostname!=(char*)0){//設(shè)置hs的bindinghostname和serverhostnamehs->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))<0)ghnbuf[0]='\0';#ifdef SERVER_NAME_LISTif ( ghnbuf[0]!='\0')hs->server_hostname=hostname_map(ghnbuf);#endifif ( hs->server_hostname==(char*)0){#ifdef SERVER_NAMEhs->server_hostname=SERVER_NAME;#elseif(ghnbuf[0]!='\0')hs->server_hostname=ghnbuf;#endif}}hs->port=port;//initialize_listen_socket,就是socket bind listenif( sa6p == (httpd_sockaddr*)0)hs->listen6_fd=-1;elsehs->listen6_fd=initialize_listen_socket(sa6p);if( sa4p == (httpd_sockaddr*)0)hs->listen4_fd=-1;elsehs->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_inhttpd_sockaddr sa4;httpd_sockaddr sa6;int gotv4, gotv6;lookup_hostname(&sa4,sizeof(sa4),&gotv4,&sa6,sizeof(sa6),&gotv6);//計算系統(tǒng)允許的fd數(shù),初始化fdwatch,io復用模式相關(guān)的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相關(guān)的。做hs初始化和socket,bind,listenhs=httpd_initialize(hostname,gotv4?&sa4:(httpd_sockaddr*)0,gotv6?&sa6:(httpd_sockaddr*)0,port); if(hs != (httpd_server*)0){if (hs->listen4_fd!=-1)//注冊監(jiān)聽fdfdw->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_ready<0){if( errno==EINTR || errno==EAGAIN)continue;exit(1);}(void) gettimeofday( &tv, (struct timezone*) 0 );if(num_ready==0){// tmr_run(&tv);continue;}//num_ready>0//accept并加入listen setif ( 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是一個系統(tǒng)調(diào)用,將程序的可見文件視圖限制到當前目錄及其下面的其他目錄。這樣其他遠程user就無法訪問初始目錄外的文件。 3 子進程也會有這樣的屬性,所以CGI文件也會有這樣的效果。 4 但是只有root才可以調(diào)用chroot,所以這意味程序只能由root啟動,但是thttpd中最后root可以轉(zhuǎn)換為其他user,也保證了這點。 5 1.限制被CHROOT的使用者所能執(zhí)行的程序 6 2.防止使用者存取某些特定檔案,如/etc/passwd。 7 3.防止入侵者/bin/rm -rf /。 8 4.提供Guest服務(wù)以及處罰惡意的使用者。 9 5.增進系統(tǒng)的安全。 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<pwd.h> 15 #include<sys/types.h> 16 #include<unistd.h> 17 #include<stdlib.h> 18 #include<sys/file.h> 19 #include<string.h> 20 #include<sys/types.h> 21 #include<grp.h> 22 #include<stdio.h> 23 #include<errno.h> 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權(quán)限,獲取將要托管的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)<0 ) 63 { 64 //error 65 printf("error chdir\n"); 66 exit(1); 67 } 68 } 69 #endif 70 71 //當前工作目錄 72 char cwd[MAXPATHLEN+1]; 73 printCwd(cwd); 74 75 //系統(tǒng)的目錄結(jié)構(gòu)將以指定的位置作為'/'的位置 76 //作用: 77 //增加了系統(tǒng)安全性,新根下訪問不到舊根目錄和文件 78 //建立一個與原系統(tǒng)隔離的系統(tǒng)目錄結(jié)構(gòu),方便用戶開發(fā) 79 //引導linux系統(tǒng)啟動以及急救系統(tǒng)等 80 //詳細見IBM文章 81 if(chroot(cwd)<0) 82 //將當前程序的工作目錄作為新的文件夾root,成功后getcwd變?yōu)?#34;/" 83 { 84 printf("error chroot\n"); 85 exit(1); 86 } 87 88 //當前的工作目錄變?yōu)?#34;/" 89 printCwd(cwd); 90 91 //在新的"/"目錄下跳轉(zhuǎn)到a文件夾 92 if ( chdir( "a" ) < 0 ) 93 { 94 //error 95 printf("error chdir2\n,%s",strerror(errno)); 96 exit( 1 ); 97 } 98 99 //路徑 "/a/" 100 printCwd(cwd); 101 102 //root完成chroot調(diào)用后,轉(zhuǎn)換身份 103 if ( getuid() == 0 ) 104 { 105 /* 106 // Set aux groups to null. 107 if ( setgroups( 0, (const gid_t*) 0 ) < 0 ) 108 { 109 printf("error setgroups\n"); 110 exit( 1 ); 111 } 112 */ 113 114 if ( setgid( gid ) < 0 ) 115 { 116 printf("error setgid\n"); 117 exit( 1 ); 118 } 119 120 #ifdef HAVE_SETLOGIN 121 (void) setlogin( user ); 122 #endif 123 124 if ( setuid( uid ) < 0 ) 125 { 126 printf("error syslog\n"); 127 exit( 1 ); 128 } 129 } 130 }

?其他模塊

總結(jié)

以上是生活随笔為你收集整理的thttpd源码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。