Commit f82c178b5bd15119bb67a393ce3d5637ab36d3bf
1 parent
9198f7e7
started a response handler and changed serverRun to use it for its response
Showing
17 changed files
with
335 additions
and
85 deletions
1 | +2012-02-10 19:57:57 +0100 Georg Hopp | ||
2 | + | ||
3 | + * started a response handler and changed serverRun to use it for its response (HEAD, master) | ||
4 | + | ||
1 | 2012-02-10 12:42:04 +0100 Georg Hopp | 5 | 2012-02-10 12:42:04 +0100 Georg Hopp |
2 | 6 | ||
3 | - * fixed bug at server destructor (HEAD, master) | 7 | + * fixed bug at server destructor (origin/master, origin/HEAD) |
4 | 8 | ||
5 | 2012-02-10 09:59:41 +0100 Georg Hopp | 9 | 2012-02-10 09:59:41 +0100 Georg Hopp |
6 | 10 | ||
@@ -12,7 +16,7 @@ | @@ -12,7 +16,7 @@ | ||
12 | 16 | ||
13 | 2012-02-10 08:14:31 +0100 Georg Hopp | 17 | 2012-02-10 08:14:31 +0100 Georg Hopp |
14 | 18 | ||
15 | - * now only use keep-alive.... (origin/master, origin/HEAD) | 19 | + * now only use keep-alive.... |
16 | 20 | ||
17 | 2012-02-10 06:36:43 +0100 Georg Hopp | 21 | 2012-02-10 06:36:43 +0100 Georg Hopp |
18 | 22 |
TODO
0 → 100644
@@ -10,8 +10,11 @@ CLASS(HttpHeader) { | @@ -10,8 +10,11 @@ CLASS(HttpHeader) { | ||
10 | }; | 10 | }; |
11 | 11 | ||
12 | HttpHeader httpHeaderParse(char * line); // @INFO: destructive | 12 | HttpHeader httpHeaderParse(char * line); // @INFO: destructive |
13 | -void httpHeaderSort(const HttpHeader [], int); | ||
14 | -char * httpHeaderGet(const HttpHeader [], int, const char *); | 13 | + |
14 | +void httpHeaderSort(const HttpHeader [], int); | ||
15 | +char * httpHeaderGet(const HttpHeader [], int, const char *); | ||
16 | +size_t httpHeaderSizeGet(HttpHeader); | ||
17 | +size_t httpHeaderToString(HttpHeader, char *); | ||
15 | 18 | ||
16 | #endif // __HTTP_HEADER_H__ | 19 | #endif // __HTTP_HEADER_H__ |
17 | 20 |
@@ -16,8 +16,8 @@ CLASS(HttpRequest) { | @@ -16,8 +16,8 @@ CLASS(HttpRequest) { | ||
16 | int nbody; | 16 | int nbody; |
17 | }; | 17 | }; |
18 | 18 | ||
19 | -char * | ||
20 | -httpRequestHeaderGet(HttpRequest this, const char * name); | 19 | +char * httpRequestHeaderGet(HttpRequest, const char *); |
20 | +char httpRequestHasKeepAlive(HttpRequest); | ||
21 | 21 | ||
22 | #endif /* __HTTP_REQUEST_H__ */ | 22 | #endif /* __HTTP_REQUEST_H__ */ |
23 | 23 |
1 | #ifndef __HTTP_RESPONSE_H__ | 1 | #ifndef __HTTP_RESPONSE_H__ |
2 | #define __HTTP_RESPONSE_H__ | 2 | #define __HTTP_RESPONSE_H__ |
3 | 3 | ||
4 | +#include <sys/types.h> | ||
5 | + | ||
4 | #include "class.h" | 6 | #include "class.h" |
7 | +#include "http/header.h" | ||
8 | + | ||
5 | 9 | ||
6 | CLASS(HttpResponse) { | 10 | CLASS(HttpResponse) { |
7 | - char * http_version; | ||
8 | - char * status; | ||
9 | - char * reson; | 11 | + char * version; |
12 | + unsigned int status; | ||
13 | + char * reason; | ||
10 | 14 | ||
11 | - HttpHeader header[128]; | ||
12 | - int nheader; | 15 | + HttpHeader header[128]; |
16 | + int nheader; | ||
13 | 17 | ||
14 | - char * body; | ||
15 | - int nbody; | 18 | + char * body; |
19 | + int nbody; | ||
16 | }; | 20 | }; |
17 | 21 | ||
18 | -char * | ||
19 | -httpRequestHeaderGet(HttpRequest this, const char * name); | 22 | +HttpResponse httpResponse404(); |
23 | + | ||
24 | +void httpResponseHeaderSet(HttpResponse, const char *, const char *); | ||
25 | +size_t httpResponseSizeGet(HttpResponse); | ||
26 | +size_t httpResponseToString(HttpResponse, char *); | ||
20 | 27 | ||
21 | #endif /* __HTTP_RESPONSE_H__ */ | 28 | #endif /* __HTTP_RESPONSE_H__ */ |
22 | 29 |
1 | ACLOCAL_AMFLAGS = -I m4 | 1 | ACLOCAL_AMFLAGS = -I m4 |
2 | AUTOMAKE_OPTIONS = subdir-objects | 2 | AUTOMAKE_OPTIONS = subdir-objects |
3 | 3 | ||
4 | -CLASS = class.c interface.c interface/class.c | 4 | +IFACE = interface/class.c interface/stream_reader.c interface/logger.c |
5 | +CLASS = class.c interface.c | ||
5 | SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c | 6 | SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c |
6 | SERVER = server.c server/run.c server/close_conn.c | 7 | SERVER = server.c server/run.c server/close_conn.c |
7 | -LOGGER = logger.c logger/stderr.c logger/syslog.c interface/logger.c | ||
8 | -HTTP = interface/stream_reader.c http/request/parser.c http/request.c \ | ||
9 | - http/request/queue.c http/header.c http/header/get.c \ | ||
10 | - http/header/sort.c http/request/parser/get_header.c \ | 8 | +LOGGER = logger.c logger/stderr.c logger/syslog.c |
9 | +REQ = http/request.c http/request/queue.c http/request/has_keep_alive.c | ||
10 | +RESP = http/response.c http/response/header_set.c \ | ||
11 | + http/response/404.c http/response/size_get.c \ | ||
12 | + http/response/to_string.c | ||
13 | +HEADER = http/header.c http/header/get.c http/header/sort.c \ | ||
14 | + http/header/size_get.c http/header/to_string.c | ||
15 | +PARSER = http/request/parser.c http/request/parser/get_header.c \ | ||
11 | http/request/parser/parse.c http/request/parser/get_request_line.c | 16 | http/request/parser/parse.c http/request/parser/get_request_line.c |
12 | 17 | ||
18 | + | ||
13 | AM_CFLAGS = -Wall -I ../include/ | 19 | AM_CFLAGS = -Wall -I ../include/ |
14 | 20 | ||
15 | bin_PROGRAMS = testserver | 21 | bin_PROGRAMS = testserver |
16 | 22 | ||
17 | testserver_SOURCES = testserver.c \ | 23 | testserver_SOURCES = testserver.c \ |
18 | - $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(HTTP) \ | ||
19 | - signalHandling.c daemonize.c | 24 | + $(IFACE) $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(REQ) \ |
25 | + $(RESP) $(HEADER) $(PARSER) signalHandling.c daemonize.c | ||
20 | testserver_CFLAGS = -Wall -I ../include/ | 26 | testserver_CFLAGS = -Wall -I ../include/ |
src/http/header/size_get.c
0 → 100644
src/http/header/to_string.c
0 → 100644
1 | +#include <string.h> | ||
2 | + | ||
3 | +#include "http/header.h" | ||
4 | + | ||
5 | +size_t | ||
6 | +httpHeaderToString(HttpHeader header, char * string) | ||
7 | +{ | ||
8 | + size_t size = httpHeaderSizeGet(header); | ||
9 | + | ||
10 | + strcpy(string, header->name); | ||
11 | + string += strlen(string); | ||
12 | + | ||
13 | + *string++ = ':'; | ||
14 | + *string++ = ' '; | ||
15 | + | ||
16 | + strcpy(string, header->value); | ||
17 | + | ||
18 | + return size; | ||
19 | +} | ||
20 | + | ||
21 | +// vim: set ts=4 sw=4: |
src/http/request/has_keep_alive.c
0 → 100644
1 | +#include <string.h> | ||
2 | +#include <ctype.h> | ||
3 | + | ||
4 | +#include "http/request.h" | ||
5 | +#include "http/header.h" | ||
6 | + | ||
7 | + | ||
8 | +char | ||
9 | +httpRequestHasKeepAlive(HttpRequest request) | ||
10 | +{ | ||
11 | + char * header; | ||
12 | + char * header_ptr; | ||
13 | + | ||
14 | + header = httpHeaderGet(request->header, request->nheader, "connection"); | ||
15 | + | ||
16 | + if (NULL == header) { | ||
17 | + return 0; | ||
18 | + } | ||
19 | + | ||
20 | + for (header_ptr = header; 0 != *header_ptr; header_ptr++) { | ||
21 | + *header_ptr = tolower(*header_ptr); | ||
22 | + } | ||
23 | + | ||
24 | + if (0 == strcmp(header, "keep-alive")) { | ||
25 | + return 1; | ||
26 | + } | ||
27 | + | ||
28 | + return 0; | ||
29 | +} | ||
30 | + | ||
31 | +// vim: set ts=4 sw=4: |
src/http/response.c
0 → 100644
1 | +#include <stdlib.h> | ||
2 | +#include <stdarg.h> | ||
3 | + | ||
4 | +#include "class.h" | ||
5 | +#include "interface/class.h" | ||
6 | + | ||
7 | +#include "http/response.h" | ||
8 | + | ||
9 | + | ||
10 | +static | ||
11 | +void | ||
12 | +_free(void ** data) | ||
13 | +{ | ||
14 | + if (NULL != *data) { | ||
15 | + free(*data); | ||
16 | + } | ||
17 | +} | ||
18 | + | ||
19 | +static | ||
20 | +void | ||
21 | +ctor(void * _this, va_list * params) | ||
22 | +{ | ||
23 | + char * version; | ||
24 | + char * reason; | ||
25 | + | ||
26 | + HttpResponse this = _this; | ||
27 | + | ||
28 | + version = va_arg(* params, char *); | ||
29 | + this->status = va_arg(* params, unsigned int); | ||
30 | + reason = va_arg(* params, char *); | ||
31 | + | ||
32 | + this->version = calloc(1, strlen(version)+1); | ||
33 | + strcpy(this->version, version); | ||
34 | + | ||
35 | + this->reason = calloc(1, strlen(reason)+1); | ||
36 | + strcpy(this->reason, reason); | ||
37 | +} | ||
38 | + | ||
39 | +static | ||
40 | +void | ||
41 | +dtor(void * _this) | ||
42 | +{ | ||
43 | + HttpResponse this = _this; | ||
44 | + int i; | ||
45 | + | ||
46 | + _free((void **)&(this->version)); | ||
47 | + _free((void **)&(this->reason)); | ||
48 | + | ||
49 | + for (i=0; i<128; i++) { | ||
50 | + if (NULL == (this->header)[i]) break; | ||
51 | + delete(&(this->header)[i]); | ||
52 | + } | ||
53 | + | ||
54 | + _free((void **)&(this->body)); | ||
55 | +} | ||
56 | + | ||
57 | +INIT_IFACE(Class, ctor, dtor, NULL); | ||
58 | +CREATE_CLASS(HttpResponse, NULL, IFACE(Class)); | ||
59 | + | ||
60 | +// vim: set ts=4 sw=4: |
src/http/response/404.c
0 → 100644
1 | +#include <stdlib.h> | ||
2 | +#include <string.h> | ||
3 | +#include <stdio.h> | ||
4 | +#include <time.h> | ||
5 | + | ||
6 | +#include "class.h" | ||
7 | +#include "interface/class.h" | ||
8 | + | ||
9 | +#include "http/response.h" | ||
10 | + | ||
11 | + | ||
12 | +#define RESP_DATA "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" \ | ||
13 | + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" \ | ||
14 | + " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" \ | ||
15 | + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" \ | ||
16 | + "<head><title>404 - Not Found</title></head>" \ | ||
17 | + "<body><h1>404 - Not Found</h1></body>" \ | ||
18 | + "</html>" | ||
19 | + | ||
20 | + | ||
21 | +HttpResponse | ||
22 | +httpResponse404() | ||
23 | +{ | ||
24 | + time_t t; | ||
25 | + struct tm * tmp; | ||
26 | + char buffer[200]; | ||
27 | + HttpResponse response; | ||
28 | + | ||
29 | + response = new(HttpResponse, "HTTP/1.1", 404, "Not Found"); | ||
30 | + | ||
31 | + httpResponseHeaderSet(response, "Content-Type", "text/html"); | ||
32 | + httpResponseHeaderSet(response, "Server", "testserver"); | ||
33 | + | ||
34 | + response->nbody = sizeof(RESP_DATA) - 1; | ||
35 | + response->body = calloc(1, sizeof(RESP_DATA)); | ||
36 | + strcpy(response->body, RESP_DATA); | ||
37 | + | ||
38 | + sprintf(buffer, "%d", response->nbody); | ||
39 | + httpResponseHeaderSet(response, "Content-Length", buffer); | ||
40 | + | ||
41 | + t = time(NULL); | ||
42 | + tmp = localtime(&t); | ||
43 | + strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp); | ||
44 | + httpResponseHeaderSet(response, "Date", buffer); | ||
45 | + | ||
46 | + return response; | ||
47 | +} | ||
48 | + | ||
49 | +// vim: set ts=4 sw=4: |
src/http/response/header_set.c
0 → 100644
1 | +#include "class.h" | ||
2 | +#include "interface/class.h" | ||
3 | + | ||
4 | +#include "http/response.h" | ||
5 | +#include "http/header.h" | ||
6 | + | ||
7 | +void | ||
8 | +httpResponseHeaderSet(HttpResponse this, const char * name, const char * value) | ||
9 | +{ | ||
10 | + (this->header)[this->nheader++] = new(HttpHeader, name, value); | ||
11 | +} | ||
12 | + | ||
13 | +// vim: set ts=4 sw=4: |
src/http/response/size_get.c
0 → 100644
1 | +#include <string.h> | ||
2 | +#include <sys/types.h> | ||
3 | + | ||
4 | +#include "http/response.h" | ||
5 | +#include "http/header.h" | ||
6 | + | ||
7 | +size_t | ||
8 | +httpResponseSizeGet(HttpResponse response) | ||
9 | +{ | ||
10 | + int i; | ||
11 | + size_t size = 0; | ||
12 | + | ||
13 | + size += strlen(response->version) + 1; | ||
14 | + size += 4; // for status | ||
15 | + size += strlen(response->reason) + 2; | ||
16 | + | ||
17 | + for (i=0; i<response->nheader; i++) { | ||
18 | + size += httpHeaderSizeGet(response->header[i]) + 2; | ||
19 | + } | ||
20 | + | ||
21 | + size += 2; | ||
22 | + size += response->nbody; | ||
23 | + | ||
24 | + return size; | ||
25 | +} | ||
26 | + | ||
27 | +// vim: set ts=4 sw=4: |
src/http/response/to_string.c
0 → 100644
1 | +#include <string.h> | ||
2 | +#include <stdio.h> | ||
3 | + | ||
4 | +#include "http/response.h" | ||
5 | +#include "http/header.h" | ||
6 | + | ||
7 | +size_t | ||
8 | +httpResponseToString(HttpResponse response, char * string) | ||
9 | +{ | ||
10 | + int i; | ||
11 | + size_t size = httpResponseSizeGet(response); | ||
12 | + char status[4]; | ||
13 | + | ||
14 | + snprintf(status, 4, "%d", response->status); | ||
15 | + | ||
16 | + strcpy(string, response->version); | ||
17 | + string += strlen(string); | ||
18 | + | ||
19 | + *string++ = ' '; | ||
20 | + | ||
21 | + strcpy(string, status); | ||
22 | + string += strlen(string); | ||
23 | + | ||
24 | + *string++ = ' '; | ||
25 | + | ||
26 | + strcpy(string, response->reason); | ||
27 | + string += strlen(string); | ||
28 | + | ||
29 | + *string++ = '\r'; | ||
30 | + *string++ = '\n'; | ||
31 | + | ||
32 | + for (i=0; i<response->nheader; i++) { | ||
33 | + string += httpHeaderToString(response->header[i], string); | ||
34 | + *string++ = '\r'; | ||
35 | + *string++ = '\n'; | ||
36 | + } | ||
37 | + | ||
38 | + *string++ = '\r'; | ||
39 | + *string++ = '\n'; | ||
40 | + | ||
41 | + memcpy(string, response->body, response->nbody); | ||
42 | + | ||
43 | + return size; | ||
44 | +} | ||
45 | + | ||
46 | +// vim: set ts=4 sw=4: |
@@ -36,14 +36,14 @@ dtor(void * _this) | @@ -36,14 +36,14 @@ dtor(void * _this) | ||
36 | Server this = _this; | 36 | Server this = _this; |
37 | int i; | 37 | int i; |
38 | 38 | ||
39 | - printf("nfds: %d\n", this->nfds); | ||
40 | - | ||
41 | for (i=1; i<this->nfds; i++) { | 39 | for (i=1; i<this->nfds; i++) { |
42 | /* | 40 | /* |
43 | * @TODO do some finalization...buffer handling...etc. | 41 | * @TODO do some finalization...buffer handling...etc. |
44 | */ | 42 | */ |
45 | delete(&(this->conns[(this->fds)[i].fd]).sock); | 43 | delete(&(this->conns[(this->fds)[i].fd]).sock); |
46 | delete(&(this->conns[(this->fds)[i].fd]).reader); | 44 | delete(&(this->conns[(this->fds)[i].fd]).reader); |
45 | + if (this->conns[(this->fds)[i].fd].wbuf) | ||
46 | + free(this->conns[(this->fds)[i].fd].wbuf); | ||
47 | } | 47 | } |
48 | 48 | ||
49 | delete(&this->sock); | 49 | delete(&this->sock); |
@@ -18,7 +18,7 @@ | @@ -18,7 +18,7 @@ | ||
18 | #include "http/request.h" | 18 | #include "http/request.h" |
19 | #include "http/request/parser.h" | 19 | #include "http/request/parser.h" |
20 | #include "http/request/queue.h" | 20 | #include "http/request/queue.h" |
21 | -#include "http/header.h" | 21 | +#include "http/response.h" |
22 | //* until here | 22 | //* until here |
23 | 23 | ||
24 | #undef MAX | 24 | #undef MAX |
@@ -81,73 +81,36 @@ serverRun(Server this) | @@ -81,73 +81,36 @@ serverRun(Server this) | ||
81 | ((HttpRequestParser)(this->conns)[fd].reader)->request_queue; | 81 | ((HttpRequestParser)(this->conns)[fd].reader)->request_queue; |
82 | 82 | ||
83 | for (j=0; j<queue->nrequests; j++) { | 83 | for (j=0; j<queue->nrequests; j++) { |
84 | - HttpRequest request = queue->requests[j]; | ||
85 | - char * header; | ||
86 | - char * header_ptr; | ||
87 | - | ||
88 | - //if (NULL != request->body) { | ||
89 | - // puts("==REQUEST BODY=="); | ||
90 | - // puts(request->body); | ||
91 | - //} | ||
92 | - | ||
93 | - header = httpHeaderGet( | ||
94 | - request->header, | ||
95 | - request->nheader, | ||
96 | - "connection"); | ||
97 | - | ||
98 | - if (NULL != header) { | ||
99 | - for (header_ptr = header; | ||
100 | - 0 != *header_ptr; | ||
101 | - header_ptr++) { | ||
102 | - *header_ptr = tolower(*header_ptr); | ||
103 | - } | ||
104 | - | ||
105 | - if (0 == strcmp(header, "keep-alive")) { | ||
106 | - (this->conns)[fd].keep_alive = 1; | ||
107 | - } | ||
108 | - } | 84 | + HttpRequest request = queue->requests[j]; |
85 | + HttpResponse response; | ||
86 | + | ||
109 | /** | 87 | /** |
110 | * @TODO: for now simply remove request and send not found. | 88 | * @TODO: for now simply remove request and send not found. |
111 | * Make this sane. | 89 | * Make this sane. |
112 | */ | 90 | */ |
91 | + response = httpResponse404(); | ||
113 | 92 | ||
114 | - delete(&request); | ||
115 | - | ||
116 | - /** | ||
117 | - * @TODO: the complete response stuff have to be removed here. | ||
118 | - */ | ||
119 | - time_t t; | ||
120 | - struct tm * tmp; | ||
121 | - char timestr[200]; | ||
122 | - | ||
123 | -#define RESP_HEAD "HTTP/1.1 404 Not Found\r\n" \ | ||
124 | - "Content-Type: text/html\r\n" \ | ||
125 | - "Content-Length: %lu\r\n" \ | ||
126 | - "Date: %s\r\n" \ | ||
127 | - "Server: testserver\r\n" | ||
128 | - | ||
129 | -#define RESP_DATA "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" \ | ||
130 | - "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" \ | ||
131 | - " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" \ | ||
132 | - "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" \ | ||
133 | - "<head><title>404 - Not Found</title></head>" \ | ||
134 | - "<body><h1>404 - Not Found</h1></body>" \ | ||
135 | - "</html>" | ||
136 | - | ||
137 | - t = time(NULL); | ||
138 | - tmp = localtime(&t); | ||
139 | - strftime(timestr, sizeof(timestr), "%a, %d %b %Y %T %Z", tmp); | ||
140 | - | ||
141 | - /** | ||
142 | - * @TODO: just to send an answer and be able to make some | ||
143 | - * apache benchs i do it here...this definetly MUST BE moved | ||
144 | - */ | ||
145 | - if ((this->conns)[fd].keep_alive) { | ||
146 | - sprintf((this->conns)[fd].wbuf, RESP_HEAD "Connection: Keep-Alive\r\n\r\n" RESP_DATA, sizeof(RESP_DATA) - 1, timestr); | 93 | + if (httpRequestHasKeepAlive(request)) { |
94 | + httpResponseHeaderSet( | ||
95 | + response, | ||
96 | + "Connection", | ||
97 | + "Keep-Alive"); | ||
147 | } | 98 | } |
148 | else { | 99 | else { |
149 | - sprintf((this->conns)[fd].wbuf, RESP_HEAD "Connection: close\r\n\r\n" RESP_DATA, sizeof(RESP_DATA) - 1, timestr); | 100 | + httpResponseHeaderSet( |
101 | + response, | ||
102 | + "Connection", | ||
103 | + "Close"); | ||
150 | } | 104 | } |
105 | + | ||
106 | + delete(&request); | ||
107 | + | ||
108 | + (this->conns)[fd].wbuf = calloc( | ||
109 | + 1, httpResponseSizeGet(response) + 1); | ||
110 | + httpResponseToString(response, (this->conns)[fd].wbuf); | ||
111 | + | ||
112 | + delete(&response); | ||
113 | + | ||
151 | (this->fds)[i].events |= POLLOUT; | 114 | (this->fds)[i].events |= POLLOUT; |
152 | } | 115 | } |
153 | 116 | ||
@@ -180,6 +143,8 @@ serverRun(Server this) | @@ -180,6 +143,8 @@ serverRun(Server this) | ||
180 | else { | 143 | else { |
181 | serverCloseConn(this, i); | 144 | serverCloseConn(this, i); |
182 | } | 145 | } |
146 | + free((this->conns)[fd].wbuf); | ||
147 | + (this->conns)[fd].wbuf = NULL; | ||
183 | } | 148 | } |
184 | else { | 149 | else { |
185 | memmove((this->conns)[fd].wbuf, | 150 | memmove((this->conns)[fd].wbuf, |
Please
register
or
login
to post a comment