# 2020q1 Homework4 (khttpd)
contributed by < `ndsl7109256` >
###### tags: `linux2020`
> [作業要求](https://hackmd.io/@sysprog/linux2020-khttpd?fbclid=IwAR1MiaCf9QKEqmWxePL3JMqZjnsIJkV_HCs0stIMLQoBPe0qz-51B3nhZNY#-%E4%BD%9C%E6%A5%AD%E8%A6%81%E6%B1%82)
> [GitHub](https://github.com/ndsl7109256/khttpd)
## How to import port to kernel
I notice that there is a function `module_param` with **DEFAULT_PORT** called in `main.c`
```c
static ushort port = DEFAULT_PORT;//DEFAULT_PORT = 8081
module_param(port, ushort, S_IRUGO);
static ushort backlog = DEFAULT_BACKLOG;
module_param(backlog,ushort, S_IRUGO);
```
Observing define of `module_param`,we can find [`__module_param_call`](https://elixir.bootlin.com/linux/v4.18/source/include/linux/moduleparam.h#L221) ,which manages parameter passing.
```c
#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \
/* Default value instead of permissions? */ \
static const char __param_str_##name[] = prefix #name; \
static struct kernel_param __moduleparam_const __param_##name \
__used \
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
= { __param_str_##name, THIS_MODULE, ops, \
VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } }
```
## Implement Fib number
I splited `request_url` in `http_request` to get the target index of Fib and import the [` bignum `](https://github.com/sysprog21/bignum) to compute the Fib number.
Also ,From `http_server_response` in `http_server.c` ,we can find that response is assigned to various of HTTP_RESPONSE.I simply changed "Hello World!" to fib number and the Content-length to the length of Fib number.
```c
static int http_server_response(struct http_request *request, int keep_alive)
{
char *response = kmalloc(BUFFER_SIZE, GFP_KERNEL);
char *reqmsg = request->request_url;
pr_info("requested_url = %s\n", request->request_url);
long long k = get_number(reqmsg);
char buf[128];
bignum_k_fast_doubling(buf, 128, k);
pr_info("fib = %s\n", buf);
if (request->method != HTTP_GET)
response = keep_alive ? HTTP_RESPONSE_501_KEEPALIVE : HTTP_RESPONSE_501;
else {
long long length;
if (keep_alive) {
snprintf(response, BUFFER_SIZE, HTTP_RESPONSE_200_KEEPALIVE_DUMMY,
strlen(buf), buf);
} else {
snprintf(response, BUFFER_SIZE, HTTP_RESPONSE_200_KEEPALIVE_DUMMY,
strlen(buf), buf);
}
}
http_server_send(request->socket, response, strlen(response));
return 0;
}
```
## Function of epoll
From [EPOLL(7) Linux Programmer's Manual](http://man7.org/linux/man-pages/man7/epoll.7.html)'s description.
>The epoll API performs a similar task to poll(2): monitoring multiple
file descriptors to see if I/O is possible on any of them. The epoll
API can be used either as an edge-triggered or a level-triggered
interface and scales well to large numbers of watched file
descriptors.
Inspect of `htstress`
```clike=
/* run test */
for (int n = 0; n < num_threads - 1; ++n)
pthread_create(&useless_thread, 0, &worker, 0);
worker(0);
```
From above code in `hstress.c`, We can know that it use thread to request from server at the same time.When the last request is end,we can know the efficiency of the server.
Interestingly, the nth thread is runming in the main program,which saves the thread creation time.
```clike=
do {
nevts = epoll_wait(efd, evts, sizeof(evts) / sizeof(evts[0]), -1);
} while (!exit_i && nevts < 0 && errno == EINTR);
...
```
from [`epoll_wait`](http://man7.org/linux/man-pages/man2/epoll_wait.2.html)
>The epoll_wait() system call waits for events on the epoll(7)
instance referred to by the file descriptor epfd. The buffer pointed
to by events is used to return information from the ready list about
file descriptors in the interest list that have some events
available.
```c=
if (evts[n].events & EPOLLOUT) {
ret = send(ec->fd, outbuf + ec->offs, outbufsize - ec->offs, 0);
...
} else if (evts[n].events & EPOLLIN) {
for (;;) {
ret = recv(ec->fd, inbuf, sizeof(inbuf), 0);
```
By the signal of evts,we can manage the process of a request, and verify if the request is good.