嵌入式Web服务器BOA移植
BOA工作流程:
1.修正BOA服务器的更目录。
static void fixup_server_root() { if (!server_root) { #ifdef SERVER_ROOT server_root = strdup(SERVER_ROOT); if (!server_root) { perror("strdup (SERVER_ROOT)"); exit(EXIT_FAILURE); } #else fputs("boa: don't know where server root is. Please #define " "SERVER_ROOT in boa.h\n" "and recompile, or use the -c command line option to " "specify it.\n", stderr); exit(EXIT_FAILURE); #endif } if (chdir(server_root) == -1) { fprintf(stderr, "Could not chdir to \"%s\": aborting\n", server_root); exit(EXIT_FAILURE); } }
2.读boa .conf配置文件。
1 /* 2 * Name: read_config_files 3 * 4 * Description: Reads config files, then makes sure that 5 * all required variables were set properly. 6 */ 7 void read_config_files(void) 8 { 9 FILE *config; 10 11 current_uid = getuid(); 12 13 if (!config_file_name) { 14 config_file_name = DEFAULT_CONFIG_FILE; 15 } 16 #ifdef ACCESS_CONTROL 17 access_init(); 18 #endif /* ACCESS_CONTROL */ 19 20 config = fopen(config_file_name, "r"); //已只读方式打开配置文件boa.conf 21 if (!config) { 22 fputs("Could not open boa.conf for reading.\n", stderr); //打印打开文件失败的信息 23 exit(EXIT_FAILURE); 24 } 25 parse(config); 26 fclose(config); 27 28 if (!server_name) { //如果没有指定服务器名字则指定服务器名字 29 struct hostent *he; 30 char temp_name[100]; 31 32 if (gethostname(temp_name, 100) == -1) { //获取服务器名字 33 perror("gethostname:"); 34 exit(EXIT_FAILURE); 35 } 36 37 he = gethostbyname(temp_name); //获取主机 38 if (he == NULL) { 39 perror("gethostbyname:"); 40 exit(EXIT_FAILURE); 41 } 42 43 server_name = strdup(he->h_name); //获取主机名 44 if (server_name == NULL) { 45 perror("strdup:"); 46 exit(EXIT_FAILURE); 47 } 48 } 49 tempdir = getenv("TMP"); 50 if (tempdir == NULL) 51 tempdir = "/tmp"; 52 53 if (single_post_limit < 0) { 54 fprintf(stderr, "Invalid value for single_post_limit: %d\n", 55 single_post_limit); 56 exit(EXIT_FAILURE); 57 } 58 59 if (vhost_root && virtualhost) { 60 fprintf(stderr, "Both VHostRoot and VirtualHost were enabled, and " 61 "they are mutually exclusive.\n"); 62 exit(EXIT_FAILURE); 63 } 64 65 if (vhost_root && document_root) { 66 fprintf(stderr, 67 "Both VHostRoot and DocumentRoot were enabled, and " 68 "they are mutually exclusive.\n"); 69 exit(EXIT_FAILURE); 70 } 71 72 if (!default_vhost) { 73 default_vhost = DEFAULT_VHOST; 74 } 75 76 #ifdef USE_SETRLIMIT 77 if (cgi_rlimit_cpu < 0) 78 cgi_rlimit_cpu = 0; 79 80 if (cgi_rlimit_data < 0) 81 cgi_rlimit_data = 0; 82 83 if (cgi_nice < 0) 84 cgi_nice = 0; 85 #endif 86 87 if (max_connections < 1) { 88 struct rlimit rl; 89 int c; 90 91 /* has not been set explicitly */ 92 c = getrlimit(RLIMIT_NOFILE, &rl); 93 if (c < 0) { 94 DIE("getrlimit"); 95 } 96 max_connections = rl.rlim_cur; 97 } 98 if (max_connections > FD_SETSIZE - 20) 99 max_connections = FD_SETSIZE - 20; 100 101 if (ka_timeout < 0) ka_timeout=0; /* not worth a message */ 102 /* save some time */ 103 default_timeout = (ka_timeout ? ka_timeout : REQUEST_TIMEOUT); 104 #ifdef HAVE_POLL 105 default_timeout *= 1000; 106 #endif 107 108 if (default_type == NULL) { 109 DIE("DefaultType *must* be set!"); 110 } 111 }
3.写日志文件。
1 /* 2 * Name: open_logs 3 * 4 * Description: Opens access log, error log, and if specified, CGI log 5 * Ties stderr to error log, except during CGI execution, at which 6 * time CGI log is the stderr for CGIs. 7 * 8 * Access log is line buffered, error log is not buffered. 9 * 10 */ 11 12 void open_logs(void) 13 { 14 int access_log; 15 16 /* if error_log_name is set, dup2 stderr to it */ 17 /* otherwise, leave stderr alone */ 18 /* we don't want to tie stderr to /dev/null */ 19 if (error_log_name) { 20 int error_log; 21 22 /* open the log file */ 23 error_log = open_gen_fd(error_log_name); 24 if (error_log < 0) { 25 DIE("unable to open error log"); 26 } 27 28 /* redirect stderr to error_log */ 29 if (dup2(error_log, STDERR_FILENO) == -1) { 30 DIE("unable to dup2 the error log"); 31 } 32 close(error_log); 33 } 34 35 if (access_log_name) { 36 access_log = open_gen_fd(access_log_name); 37 } else { 38 access_log = open("/dev/null", 0); 39 } 40 if (access_log < 0) { 41 DIE("unable to open access log"); 42 } 43 44 if (dup2(access_log, STDOUT_FILENO) == -1) { 45 DIE("can't dup2 /dev/null to STDOUT_FILENO"); 46 } 47 if (fcntl(access_log, F_SETFD, 1) == -1) { 48 DIE("unable to set close-on-exec flag for access_log"); 49 } 50 51 close(access_log); 52 53 if (cgi_log_name) { 54 cgi_log_fd = open_gen_fd(cgi_log_name); 55 if (cgi_log_fd == -1) { 56 WARN("open cgi_log"); 57 free(cgi_log_name); 58 cgi_log_name = NULL; 59 cgi_log_fd = 0; 60 } else { 61 if (fcntl(cgi_log_fd, F_SETFD, 1) == -1) { 62 WARN("unable to set close-on-exec flag for cgi_log"); 63 free(cgi_log_name); 64 cgi_log_name = NULL; 65 close(cgi_log_fd); 66 cgi_log_fd = 0; 67 } 68 } 69 } 70 #ifdef SETVBUF_REVERSED 71 setvbuf(stderr, _IONBF, (char *) NULL, 0); 72 setvbuf(stdout, _IOLBF, (char *) NULL, 0); 73 #else 74 setvbuf(stderr, (char *) NULL, _IONBF, 0); 75 setvbuf(stdout, (char *) NULL, _IOLBF, 0); 76 #endif 77 }
4.初始化Web服务器。
1 static int create_server_socket(void) 2 { 3 int server_s; 4 5 server_s = socket(SERVER_PF, SOCK_STREAM, IPPROTO_TCP); 6 if (server_s == -1) { 7 DIE("unable to create socket"); 8 } 9 10 /* server socket is nonblocking */ 11 if (set_nonblock_fd(server_s) == -1) { 12 DIE("fcntl: unable to set server socket to nonblocking"); 13 } 14 15 /* close server socket on exec so CGIs can't write to it */ 16 if (fcntl(server_s, F_SETFD, 1) == -1) { 17 DIE("can't set close-on-exec on server socket!"); 18 } 19 20 /* reuse socket addr */ 21 if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt, 22 sizeof (sock_opt))) == -1) { 23 DIE("setsockopt"); 24 } 25 26 /* Internet family-specific code encapsulated in bind_server() */ 27 if (bind_server(server_s, server_ip, server_port) == -1) { 28 DIE("unable to bind"); 29 } 30 31 /* listen: large number just in case your kernel is nicely tweaked */ 32 if (listen(server_s, backlog) == -1) { 33 DIE("unable to listen"); 34 } 35 return server_s; 36 }
5.当有客户端连接请求到达时,Web服务器(BOA)负责接收客户端请求,并保存相关请求信息。
6.当收到客户端的连接请求之后,Web服务器分析客户端请求,解析出请求的方法、URL目标、可选的查询信息及表单信息,同时根据客户端的请求做出相应的处理。
7.Web服务器处理完客户端的请求后,向客户端发送响应信息,最后关闭与客户机的TCP连接。
BOA配置信息:
1 # Boa v0.94 configuration file 2 # File format has not changed from 0.93 3 # File format has changed little from 0.92 4 # version changes are noted in the comments 5 # 6 # The Boa configuration file is parsed with a custom parser. If it 7 # reports an error, the line number will be provided; it should be easy 8 # to spot. The syntax of each of these rules is very simple, and they 9 # can occur in any order. Where possible these directives mimic those 10 # of NCSA httpd 1.3; I saw no reason to introduce gratuitous 11 # differences. 12 13 # $Id: boa.conf,v 1.3.2.6 2003/02/02 05:02:22 jnelson Exp $ 14 15 # The "ServerRoot" is not in this configuration file. It can be 16 # compiled into the server (see defines.h) or specified on the command 17 # line with the -c option, for example: 18 # 19 # boa -c /usr/local/boa 20 21 22 # Port: The port Boa runs on. The default port for http servers is 80. 23 # If it is less than 1024, the server must be started as root. 24 25 Port 80 26 27 # Listen: the Internet address to bind(2) to. If you leave it out, 28 # it takes the behavior before 0.93.17.2, which is to bind to all 29 # addresses (INADDR_ANY). You only get one "Listen" directive, 30 # if you want service on multiple IP addresses, you have three choices: 31 # 1. Run boa without a "Listen" directive 32 # a. All addresses are treated the same; makes sense if the addresses 33 # are localhost, ppp, and eth0. 34 # b. Use the VirtualHost directive below to point requests to different 35 # files. Should be good for a very large number of addresses (web 36 # hosting clients). 37 # 2. Run one copy of boa per IP address, each has its own configuration 38 # with a "Listen" directive. No big deal up to a few tens of addresses. 39 # Nice separation between clients. 40 # The name you provide gets run through inet_aton(3), so you have to use dotted 41 # quad notation. This configuration is too important to trust some DNS. 42 43 #Listen 192.68.0.5 44 45 # User: The name or UID the server should run as. 46 # Group: The group name or GID the server should run as. 47 48 User nobody 49 Group nogroup 50 51 # ServerAdmin: The email address where server problems should be sent. 52 # Note: this is not currently used, except as an environment variable 53 # for CGIs. 54 55 #ServerAdmin root@localhost 56 57 # PidFile: where to put the pid of the process. 58 # Comment out to write no pid file. 59 # Note: Because Boa drops privileges at startup, and the 60 # pid file is written by the UID/GID before doing so, Boa 61 # does not attempt removal of the pid file. 62 # PidFile /var/run/boa.pid 63 64 # ErrorLog: The location of the error log file. If this does not start 65 # with /, it is considered relative to the server root. 66 # Set to /dev/null if you don't want errors logged. 67 # If unset, defaults to /dev/stderr 68 # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 69 # is somewhat experimental and might fail under heavy load. 70 # "Usual libc implementations of printf will stall the whole 71 # process if the receiving end of a pipe stops reading." 72 #ErrorLog "|/usr/sbin/cronolog --symlink=/var/log/boa/error_log /var/log/boa/error-%Y%m%d.log" 73 74 ErrorLog /var/log/boa/error_log 75 76 # AccessLog: The location of the access log file. If this does not 77 # start with /, it is considered relative to the server root. 78 # Comment out or set to /dev/null (less effective) to disable. 79 # Useful to set to /dev/stdout for use with daemontools. 80 # Access logging. 81 # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 82 # is somewhat experimental and might fail under heavy load. 83 # "Usual libc implementations of printf will stall the whole 84 # process if the receiving end of a pipe stops reading." 85 #AccessLog "|/usr/sbin/cronolog --symlink=/var/log/boa/access_log /var/log/boa/access-%Y%m%d.log" 86 87 AccessLog /var/log/boa/access_log 88 89 # CGILog /var/log/boa/cgi_log 90 # CGILog: The location of the CGI stderr log file. If this does not 91 # start with /, it is considered relative to the server root. 92 # The log file would contain any contents send to /dev/stderr 93 # by the CGI. If this is commented out, it defaults to whatever 94 # ErrorLog points. Set to /dev/null to disable CGI stderr logging. 95 # Please NOTE: Sending the logs to a pipe ('|'), as shown below, 96 # is somewhat experimental and might fail under heavy load. 97 # "Usual libc implementations of printf will stall the whole 98 # process if the receiving end of a pipe stops reading." 99 #CGILog "|/usr/sbin/cronolog --symlink=/var/log/boa/cgi_log /var/log/boa/cgi-%Y%m%d.log" 100 101 # CGIumask 027 (no mask for user, read-only for group, and nothing for user) 102 # CGIumask 027 103 # The CGIumask is set immediately before execution of the CGI. 104 105 # UseLocaltime: Logical switch. Uncomment to use localtime 106 # instead of UTC time 107 #UseLocaltime 108 109 # VerboseCGILogs: this is just a logical switch. 110 # It simply notes the start and stop times of cgis in the error log 111 # Comment out to disable. 112 113 #VerboseCGILogs 114 115 # ServerName: the name of this server that should be sent back to 116 # clients if different than that returned by gethostname + gethostbyname 117 118 #ServerName www.your.org.here 119 120 # VirtualHost: a logical switch. 121 # Comment out to disable. 122 # Given DocumentRoot /var/www, requests on interface 'A' or IP 'IP-A' 123 # become /var/www/IP-A. 124 # Example: http://localhost/ becomes /var/www/127.0.0.1 125 # 126 # Not used until version 0.93.17.2. This "feature" also breaks commonlog 127 # output rules, it prepends the interface number to each access_log line. 128 # You are expected to fix that problem with a postprocessing script. 129 130 #VirtualHost 131 132 133 # VHostRoot: the root location for all virtually hosted data 134 # Comment out to disable. 135 # Incompatible with 'Virtualhost' and 'DocumentRoot'!! 136 # Given VHostRoot /var/www, requests to host foo.bar.com, 137 # where foo.bar.com is ip a.b.c.d, 138 # become /var/www/a.b.c.d/foo.bar.com 139 # Hostnames are "cleaned", and must conform to the rules 140 # specified in rfc1034, which are be summarized here: 141 # 142 # Hostnames must start with a letter, end with a letter or digit, 143 # and have as interior characters only letters, digits, and hyphen. 144 # Hostnames must not exceed 63 characters in length. 145 146 #VHostRoot /var/www 147 148 # DefaultVHost 149 # Define this in order to have a default hostname when the client does not 150 # specify one, if using VirtualHostName. If not specified, the word 151 # "default" will be used for compatibility with older clients. 152 153 #DefaultVHost foo.bar.com 154 155 # DocumentRoot: The root directory of the HTML documents. 156 # Comment out to disable server non user files. 157 158 DocumentRoot /var/www 159 160 # UserDir: The name of the directory which is appended onto a user's home 161 # directory if a ~user request is received. 162 163 UserDir public_html 164 165 # DirectoryIndex: Name of the file to use as a pre-written HTML 166 # directory index. Please MAKE AND USE THESE FILES. On the 167 # fly creation of directory indexes can be _slow_. 168 # Comment out to always use DirectoryMaker 169 170 DirectoryIndex index.html 171 172 # DirectoryMaker: Name of program used to create a directory listing. 173 # Comment out to disable directory listings. If both this and 174 # DirectoryIndex are commented out, accessing a directory will give 175 # an error (though accessing files in the directory are still ok). 176 177 DirectoryMaker /usr/lib/boa/boa_indexer 178 179 # DirectoryCache: If DirectoryIndex doesn't exist, and DirectoryMaker 180 # has been commented out, the the on-the-fly indexing of Boa can be used 181 # to generate indexes of directories. Be warned that the output is 182 # extremely minimal and can cause delays when slow disks are used. 183 # Note: The DirectoryCache must be writable by the same user/group that 184 # Boa runs as. 185 186 # DirectoryCache /var/spool/boa/dircache 187 188 # KeepAliveMax: Number of KeepAlive requests to allow per connection 189 # Comment out, or set to 0 to disable keepalive processing 190 191 KeepAliveMax 1000 192 193 # KeepAliveTimeout: seconds to wait before keepalive connection times out 194 195 KeepAliveTimeout 10 196 197 # MimeTypes: This is the file that is used to generate mime type pairs 198 # and Content-Type fields for boa. 199 # Set to /dev/null if you do not want to load a mime types file. 200 # Do *not* comment out (better use AddType!) 201 202 MimeTypes /etc/mime.types 203 204 # DefaultType: MIME type used if the file extension is unknown, or there 205 # is no file extension. 206 207 DefaultType text/plain 208 209 # CGIPath: The value of the $PATH environment variable given to CGI progs. 210 211 CGIPath /bin:/usr/bin:/usr/local/bin 212 213 # SinglePostLimit: The maximum allowable number of bytes in 214 # a single POST. Default is normally 1MB. 215 216 # AddType: adds types without editing mime.types 217 # Example: AddType type extension [extension ...] 218 219 # Uncomment the next line if you want .cgi files to execute from anywhere 220 #AddType application/x-httpd-cgi cgi 221 222 # Redirect, Alias, and ScriptAlias all have the same semantics -- they 223 # match the beginning of a request and take appropriate action. Use 224 # Redirect for other servers, Alias for the same server, and ScriptAlias 225 # to enable directories for script execution. 226 227 # Redirect allows you to tell clients about documents which used to exist in 228 # your server's namespace, but do not anymore. This allows you to tell the 229 # clients where to look for the relocated document. 230 # Example: Redirect /bar http://elsewhere/feh/bar 231 232 # Aliases: Aliases one path to another. 233 # Example: Alias /path1/bar /path2/foo 234 235 Alias /doc /usr/doc 236 237 # ScriptAlias: Maps a virtual path to a directory for serving scripts 238 # Example: ScriptAlias /htbin/ /www/htbin/ 239 240 ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
BOA源码:
编译BOA源码:
#tar zxvf boa-0.94.14.tar.gz
#cd boa-0.94.tar.gz/src/
#./configure
#make
设置BOA配置信息
1.建立boa.conf配置文件的路径,并复制boa.conf文件到该目录下。
#mkdir /etc/toa
#cp boa.conf /etc/boa
2.建立日志目录/var/log/boa。
#mkdir /var/log/boa
3.修改配置信息:
# User: The name or UID the server should run as.
# Group: The group name or GID the server should run as.
User nobody
Group nogroup 改为 Group 0
# CGIPath: The value of the $PATH environment variable given to CGI progs.
CGIPath /bin:/usr/bin:/usr/local/bin 修改为:CGIPath /bin:/usr/bin:/var/lwww/cgi-bin
# DirectoryMaker: Name of program used to create a directory listing.
# Comment out to disable directory listings. If both this and
# DirectoryIndex are commented out, accessing a directory will give
# an error (though accessing files in the directory are still ok).
DirectoryMaker /usr/lib/boa/boa_indexer
# ScriptAlias: Maps a virtual path to a directory for serving scripts
# Example: ScriptAlias /htbin/ /www/htbin/
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ 修改为ScripAlias /cgi-bin/ /var/www/cgi-bin
# ServerName: the name of this server that should be sent back to
# clients if different than that returned by gethostname + gethostbyname
ServerName www.your.org.here
测试BOA
1.编写测试主页index.html
<% page contentType="text/html; charset=gb2313" %》 <! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <title> boa test page! </title> <head><font color="#cc2200"><b></b>欢迎大家测试BOA服务器</font><p> </head> <body> 测试BOA服务器测试页。 </body> </html>
2.启动Web服务器
#./boa
#ps