struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options) { struct bufferevent_private *bufev_p; struct bufferevent *bufev; #ifdef _WIN32 if (base && event_base_get_iocp_(base)) return bufferevent_async_new_(base, fd, options); #endif if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL) return NULL; if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket, options) < 0) { mm_free(bufev_p); return NULL; } bufev = &bufev_p->bev; evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); event_assign(&bufev->ev_read, bufev->ev_base, fd, EV_READ|EV_PERSIST, bufferevent_readcb, bufev); event_assign(&bufev->ev_write, bufev->ev_base, fd, EV_WRITE|EV_PERSIST, bufferevent_writecb, bufev); evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev); evbuffer_freeze(bufev->input, 0); evbuffer_freeze(bufev->output, 1); return bufev; }
struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options) { struct bufferevent_private *bufev_p; struct bufferevent *bufev; #ifdef WIN32 if (base && event_base_get_iocp(base)) return bufferevent_async_new(base, fd, options); #endif if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL) return NULL; if (bufferevent_init_common(bufev_p, base, &bufferevent_ops_socket, options) < 0) { mm_free(bufev_p); return NULL; } bufev = &bufev_p->bev; //设置将evbuffer的数据向fd传 evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); //设置读写回调 event_assign(&bufev->ev_read, bufev->ev_base, fd, EV_READ|EV_PERSIST, bufferevent_readcb, bufev); event_assign(&bufev->ev_write, bufev->ev_base, fd, EV_WRITE|EV_PERSIST, bufferevent_writecb, bufev); //设置evbuffer的回调函数,使得外界给写缓冲区添加数据时,能触发 //写操作,这个回调对于写事件的监听是很重要的 evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev); /* 虽然这里冻结了,但实际上Libevent在读数据或者写数据之前会解冻的读完或者写完数据后,又会马上冻结。 * 这主要防止数据被意外修改。用户一般不会直接调用evbuffer_freeze或者evbuffer_unfreeze函数。 * 一切的冻结和解冻操作都由Libevent内部完成。还有一点要注意,因为这里只是把写缓冲区的头部冻结了。 * 所以还是可以往写缓冲区的尾部追加数据。同样,此时也是可以从读缓冲区读取数据。这个是必须的。 * 因为在Libevent内部不解冻的时候,用户需要从读缓冲区中获取数据(这相当于从socket fd中读取数据), * 用户也需要把数据写到写缓冲区中(这相当于把数据写入到socket fd中)。*/ //冻结读缓冲区的尾部,未解冻之前不能往读缓冲区追加数据 //也就是说不能从socket fd中读取数据 evbuffer_freeze(bufev->input, 0); //冻结写缓冲区的头部,未解冻之前不能把写缓冲区的头部数据删除 //也就是说不能把数据写到socket fd evbuffer_freeze(bufev->output, 1); return bufev; }
/** * Called by libevent when there is data to read. */ void buffered_on_read(struct bufferevent *bev, void *arg) { client_t *client = (client_t *)arg; char *line; size_t n; /* If we have input data, the number of bytes we have is contained in * bev->input->off. Copy the data from the input buffer to the output * buffer in 4096-byte chunks. There is a one-liner to do the whole thing * in one shot, but the purpose of this server is to show actual real-world * reading and writing of the input and output buffers, so we won't take * that shortcut here. */ struct evbuffer *input = bufferevent_get_input(bev); line = evbuffer_readln(input, &n, EVBUFFER_EOL_CRLF); char cmd[256], protocol[256], path[MAX_PATH_SIZE]; httpHeader_t httpHeader; httpHeader.command = UNKNOWN_C; httpHeader.status = OK; if (n != 0) { int scaned = sscanf(line, "%s %s %s\n", cmd, path, protocol); if (scaned == 3) { if (!strcmp(cmd, "GET")) { httpHeader.command = GET; } else if (!strcmp(cmd, "HEAD")) { httpHeader.command = HEAD; } else { httpHeader.command = UNKNOWN_C; } /* if (strcmp(protocol, "HTTP/1.1")) { printf("BAD PROTOCOL%s\n", protocol); httpHeader.status = BAD_REQUEST; }*/ if (path[0] != '/') { printf("BAD INPUtT\n"); httpHeader.status = BAD_REQUEST; } urlDecode(path); httpHeader.type = getContentType(path); if (getDepth(path) == -1) { printf("BAD DEPTH\n"); httpHeader.status = BAD_REQUEST; } } else { printf("Bad scanned\n"); httpHeader.status = BAD_REQUEST; } } else { printf("OOO BAD N\n"); httpHeader.status = BAD_REQUEST; } switch (httpHeader.status) { case BAD_REQUEST: printf("Bad request\n"); break; case OK: printf("OK\n"); break; case NOT_FOUND: printf("NOt found\n"); break; } switch (httpHeader.command) { case UNKNOWN_C: printf("UNKNOWS\n"); break; case GET: printf("GET\n"); break; case HEAD: printf("HEAD\n"); break; } printf("%s\n", path); free(line); if (httpHeader.status != BAD_REQUEST) { char fullPath[2048] = {'\0'}; strcpy(fullPath, ROOT_PATH); strcat(fullPath, path); int fd = open(fullPath, O_RDONLY); if (fd < 0) { httpHeader.status = NOT_FOUND; printf("Can't open %s", fullPath); } client->openFd = -1; struct stat st; httpHeader.length = lseek(fd, 0, SEEK_END); if (httpHeader.length == -1 || lseek(fd, 0, SEEK_SET) == -1) { httpHeader.status = BAD_REQUEST; printf("Cant seek\n"); } addHeader(&httpHeader, client->output_buffer); if (fstat(fd, &st) < 0) { perror("fstat"); } if (fd != -1 && httpHeader.status == OK && httpHeader.command == GET) { evbuffer_set_flags(client->output_buffer, EVBUFFER_FLAG_DRAINS_TO_FD); if(evbuffer_add_file(client->output_buffer, fd, 0, httpHeader.length) != 0) { perror("add file"); } } // printf("%d\n", fd); } //evbuffer_add(client->output_buffer, "AAA", 3); /* while ((line = evbuffer_readln(input, &n, EVBUFFER_EOL_CRLF))) { evbuffer_add(client->output_buffer, line, n); evbuffer_add(client->output_buffer, "\n", 1); free(line); }*/ //evbuffer_add_printf(client->output_buffer, "HTTP/1.1 200 OK\r\rContent-Type: text/html\r\nDate: Sun, 14 Sep 2014 08:39:53 GMT\r\nContent-Length: 5\r\n\r\n OKK\r\n"); // while (evbuffer_get_length(input) > 0) { /* Remove a chunk of data from the input buffer, copying it into our * local array (data). */ // nbytes = evbuffer_remove(input, data, 4096); /* Add the chunk of data from our local array (data) to the client's * output buffer. */ // evbuffer_add(client->output_buffer, data, nbytes); //} /* Send the results to the client. This actually only queues the results * for sending. Sending will occur asynchronously, handled by libevent. */ if (bufferevent_write_buffer(bev, client->output_buffer) == -1) { errorOut("Error sending data to client on fd %d\n", client->fd); } //bufferevent_setcb(bev, NULL, buffered_on_write, NULL, NULL); //bufferevent_enable(bev, EV_WRITE); }
static void static_files_cb(struct evhttp_request *req, void *arg) { http_serverlog_request(req); const char *static_root = arg; apr_pool_t *local_pool; const char *full_name; struct stat64 file_stat; const char *mime_type; if(!static_root) { LOG4C_ERROR(logger, "static root not configured"); evhttp_send_error(req, HTTP_NOTFOUND, "Static file server not configured"); return; } const char *uri = evhttp_request_get_uri(req); if (strstr(uri, "..") != NULL) { LOG4C_ERROR(logger, "illegal URL"); evhttp_send_error(req, HTTP_BADREQUEST, "Illegal URL"); return; } CREATE_POOL(local_pool, NULL); const char *path = get_path_from_uri(local_pool, uri); mime_type = guess_mime_type(uri); LOG4C_DEBUG(logger, "mime type is %s", mime_type); full_name = apr_pstrcat(local_pool, static_root, "/", path, NULL); if (lstat64(full_name, &file_stat) < 0) { LOG4C_ERROR(logger, "file not found"); evhttp_send_error(req, HTTP_NOTFOUND, NULL); return; } int fd = open(full_name, O_RDONLY); if (fd < 0) { LOG4C_ERROR(logger, "open failed"); evhttp_send_error(req, HTTP_NOTFOUND, NULL); return; } struct evbuffer *rep_buf = evbuffer_new(); evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", mime_type); evbuffer_set_flags(rep_buf, EVBUFFER_FLAG_DRAINS_TO_FD); //TODO: LIBEVENT DOES NOT SUPPORT LARGE FILES - USES off_t BUT _FILE_OFFSET_BITS=64 IS NOT DEFINED! evbuffer_add_file(rep_buf, fd, 0, file_stat.st_size); // evhttp_send_reply(req, HTTP_OK, "OK", rep_buf); evbuffer_free(rep_buf); RELEASE_POOL(local_pool); }