Annotation of embedaddon/lighttpd/src/connections-glue.c, revision 1.1.1.2
1.1.1.2 ! misho 1: #include "first.h"
! 2:
1.1 misho 3: #include "base.h"
4: #include "connections.h"
1.1.1.2 ! misho 5: #include "joblist.h"
! 6: #include "log.h"
! 7:
! 8: #include <errno.h>
! 9:
! 10: #ifdef USE_OPENSSL
! 11: # include <openssl/ssl.h>
! 12: # include <openssl/err.h>
! 13: #endif
1.1 misho 14:
15: const char *connection_get_state(connection_state_t state) {
16: switch (state) {
17: case CON_STATE_CONNECT: return "connect";
18: case CON_STATE_READ: return "read";
19: case CON_STATE_READ_POST: return "readpost";
20: case CON_STATE_WRITE: return "write";
21: case CON_STATE_CLOSE: return "close";
22: case CON_STATE_ERROR: return "error";
23: case CON_STATE_HANDLE_REQUEST: return "handle-req";
24: case CON_STATE_REQUEST_START: return "req-start";
25: case CON_STATE_REQUEST_END: return "req-end";
26: case CON_STATE_RESPONSE_START: return "resp-start";
27: case CON_STATE_RESPONSE_END: return "resp-end";
28: default: return "(unknown)";
29: }
30: }
31:
32: const char *connection_get_short_state(connection_state_t state) {
33: switch (state) {
34: case CON_STATE_CONNECT: return ".";
35: case CON_STATE_READ: return "r";
36: case CON_STATE_READ_POST: return "R";
37: case CON_STATE_WRITE: return "W";
38: case CON_STATE_CLOSE: return "C";
39: case CON_STATE_ERROR: return "E";
40: case CON_STATE_HANDLE_REQUEST: return "h";
41: case CON_STATE_REQUEST_START: return "q";
42: case CON_STATE_REQUEST_END: return "Q";
43: case CON_STATE_RESPONSE_START: return "s";
44: case CON_STATE_RESPONSE_END: return "S";
45: default: return "x";
46: }
47: }
48:
49: int connection_set_state(server *srv, connection *con, connection_state_t state) {
50: UNUSED(srv);
51:
52: con->state = state;
53:
54: return 0;
55: }
56:
1.1.1.2 ! misho 57: #if 0
! 58: static void dump_packet(const unsigned char *data, size_t len) {
! 59: size_t i, j;
! 60:
! 61: if (len == 0) return;
! 62:
! 63: for (i = 0; i < len; i++) {
! 64: if (i % 16 == 0) fprintf(stderr, " ");
! 65:
! 66: fprintf(stderr, "%02x ", data[i]);
! 67:
! 68: if ((i + 1) % 16 == 0) {
! 69: fprintf(stderr, " ");
! 70: for (j = 0; j <= i % 16; j++) {
! 71: unsigned char c;
! 72:
! 73: if (i-15+j >= len) break;
! 74:
! 75: c = data[i-15+j];
! 76:
! 77: fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
! 78: }
! 79:
! 80: fprintf(stderr, "\n");
! 81: }
! 82: }
! 83:
! 84: if (len % 16 != 0) {
! 85: for (j = i % 16; j < 16; j++) {
! 86: fprintf(stderr, " ");
! 87: }
! 88:
! 89: fprintf(stderr, " ");
! 90: for (j = i & ~0xf; j < len; j++) {
! 91: unsigned char c;
! 92:
! 93: c = data[j];
! 94: fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
! 95: }
! 96: fprintf(stderr, "\n");
! 97: }
! 98: }
! 99: #endif
! 100:
! 101: static int connection_handle_read_ssl(server *srv, connection *con) {
! 102: #ifdef USE_OPENSSL
! 103: int r, ssl_err, len;
! 104: char *mem = NULL;
! 105: size_t mem_len = 0;
! 106:
! 107: if (!con->srv_socket->is_ssl) return -1;
! 108:
! 109: ERR_clear_error();
! 110: do {
! 111: chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, SSL_pending(con->ssl));
! 112: #if 0
! 113: /* overwrite everything with 0 */
! 114: memset(mem, 0, mem_len);
! 115: #endif
! 116:
! 117: len = SSL_read(con->ssl, mem, mem_len);
! 118: if (len > 0) {
! 119: chunkqueue_use_memory(con->read_queue, len);
! 120: con->bytes_read += len;
! 121: } else {
! 122: chunkqueue_use_memory(con->read_queue, 0);
! 123: }
! 124:
! 125: if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
! 126: log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
! 127: connection_set_state(srv, con, CON_STATE_ERROR);
! 128: return -1;
! 129: }
! 130: } while (len > 0);
! 131:
! 132: if (len < 0) {
! 133: int oerrno = errno;
! 134: switch ((r = SSL_get_error(con->ssl, len))) {
! 135: case SSL_ERROR_WANT_WRITE:
! 136: con->is_writable = -1;
! 137: case SSL_ERROR_WANT_READ:
! 138: con->is_readable = 0;
! 139:
! 140: /* the manual says we have to call SSL_read with the same arguments next time.
! 141: * we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway.
! 142: */
! 143:
! 144: return 0;
! 145: case SSL_ERROR_SYSCALL:
! 146: /**
! 147: * man SSL_get_error()
! 148: *
! 149: * SSL_ERROR_SYSCALL
! 150: * Some I/O error occurred. The OpenSSL error queue may contain more
! 151: * information on the error. If the error queue is empty (i.e.
! 152: * ERR_get_error() returns 0), ret can be used to find out more about
! 153: * the error: If ret == 0, an EOF was observed that violates the
! 154: * protocol. If ret == -1, the underlying BIO reported an I/O error
! 155: * (for socket I/O on Unix systems, consult errno for details).
! 156: *
! 157: */
! 158: while((ssl_err = ERR_get_error())) {
! 159: /* get all errors from the error-queue */
! 160: log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
! 161: r, ERR_error_string(ssl_err, NULL));
! 162: }
! 163:
! 164: switch(oerrno) {
! 165: default:
! 166: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
! 167: len, r, oerrno,
! 168: strerror(oerrno));
! 169: break;
! 170: }
! 171:
! 172: break;
! 173: case SSL_ERROR_ZERO_RETURN:
! 174: /* clean shutdown on the remote side */
! 175:
! 176: if (r == 0) {
! 177: /* FIXME: later */
! 178: }
! 179:
! 180: /* fall thourgh */
! 181: default:
! 182: while((ssl_err = ERR_get_error())) {
! 183: switch (ERR_GET_REASON(ssl_err)) {
! 184: case SSL_R_SSL_HANDSHAKE_FAILURE:
! 185: #ifdef SSL_R_TLSV1_ALERT_UNKNOWN_CA
! 186: case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
! 187: #endif
! 188: #ifdef SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN
! 189: case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
! 190: #endif
! 191: #ifdef SSL_R_SSLV3_ALERT_BAD_CERTIFICATE
! 192: case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
! 193: #endif
! 194: if (!con->conf.log_ssl_noise) continue;
! 195: break;
! 196: default:
! 197: break;
! 198: }
! 199: /* get all errors from the error-queue */
! 200: log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
! 201: r, ERR_error_string(ssl_err, NULL));
! 202: }
! 203: break;
! 204: }
! 205:
! 206: connection_set_state(srv, con, CON_STATE_ERROR);
! 207:
! 208: return -1;
! 209: } else if (len == 0) {
! 210: con->is_readable = 0;
! 211: /* the other end close the connection -> KEEP-ALIVE */
! 212:
! 213: return -2;
! 214: } else {
! 215: return 0;
! 216: }
! 217: #else
! 218: UNUSED(srv);
! 219: UNUSED(con);
! 220: return -1;
! 221: #endif
! 222: }
! 223:
! 224: /* 0: everything ok, -1: error, -2: con closed */
! 225: int connection_handle_read(server *srv, connection *con) {
! 226: int len;
! 227: char *mem = NULL;
! 228: size_t mem_len = 0;
! 229: int toread;
! 230:
! 231: if (con->srv_socket->is_ssl) {
! 232: return connection_handle_read_ssl(srv, con);
! 233: }
! 234:
! 235: /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
! 236: * us more than 4kb is available
! 237: * if FIONREAD doesn't signal a big chunk we fill the previous buffer
! 238: * if it has >= 1kb free
! 239: */
! 240: #if defined(__WIN32)
! 241: chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, 4096);
! 242:
! 243: len = recv(con->fd, mem, mem_len, 0);
! 244: #else /* __WIN32 */
! 245: if (ioctl(con->fd, FIONREAD, &toread) || toread <= 4*1024) {
! 246: toread = 4096;
! 247: }
! 248: else if (toread > MAX_READ_LIMIT) {
! 249: toread = MAX_READ_LIMIT;
! 250: }
! 251: chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, toread);
! 252:
! 253: len = read(con->fd, mem, mem_len);
! 254: #endif /* __WIN32 */
! 255:
! 256: chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
! 257:
! 258: if (len < 0) {
! 259: con->is_readable = 0;
! 260:
! 261: #if defined(__WIN32)
! 262: {
! 263: int lastError = WSAGetLastError();
! 264: switch (lastError) {
! 265: case EAGAIN:
! 266: return 0;
! 267: case EINTR:
! 268: /* we have been interrupted before we could read */
! 269: con->is_readable = 1;
! 270: return 0;
! 271: case ECONNRESET:
! 272: /* suppress logging for this error, expected for keep-alive */
! 273: break;
! 274: default:
! 275: log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - recv failed: ", lastError);
! 276: break;
! 277: }
! 278: }
! 279: #else /* __WIN32 */
! 280: switch (errno) {
! 281: case EAGAIN:
! 282: return 0;
! 283: case EINTR:
! 284: /* we have been interrupted before we could read */
! 285: con->is_readable = 1;
! 286: return 0;
! 287: case ECONNRESET:
! 288: /* suppress logging for this error, expected for keep-alive */
! 289: break;
! 290: default:
! 291: log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
! 292: break;
! 293: }
! 294: #endif /* __WIN32 */
! 295:
! 296: connection_set_state(srv, con, CON_STATE_ERROR);
! 297:
! 298: return -1;
! 299: } else if (len == 0) {
! 300: con->is_readable = 0;
! 301: /* the other end close the connection -> KEEP-ALIVE */
! 302:
! 303: /* pipelining */
! 304:
! 305: return -2;
! 306: } else if (len != (ssize_t) mem_len) {
! 307: /* we got less then expected, wait for the next fd-event */
! 308:
! 309: con->is_readable = 0;
! 310: }
! 311:
! 312: con->bytes_read += len;
! 313: #if 0
! 314: dump_packet(b->ptr, len);
! 315: #endif
! 316:
! 317: return 0;
! 318: }
! 319:
! 320: handler_t connection_handle_read_post_state(server *srv, connection *con) {
! 321: chunkqueue *cq = con->read_queue;
! 322: chunkqueue *dst_cq = con->request_content_queue;
! 323:
! 324: int is_closed = 0;
! 325:
! 326: if (con->is_readable) {
! 327: con->read_idle_ts = srv->cur_ts;
! 328:
! 329: switch(connection_handle_read(srv, con)) {
! 330: case -1:
! 331: return HANDLER_ERROR;
! 332: case -2:
! 333: is_closed = 1;
! 334: break;
! 335: default:
! 336: break;
! 337: }
! 338: }
! 339:
! 340: chunkqueue_remove_finished_chunks(cq);
! 341:
! 342: if (con->request.content_length <= 64*1024) {
! 343: /* don't buffer request bodies <= 64k on disk */
! 344: chunkqueue_steal(dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in);
! 345: }
! 346: else if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in)) {
! 347: /* writing to temp file failed */
! 348: con->http_status = 500; /* Internal Server Error */
! 349: con->keep_alive = 0;
! 350: con->mode = DIRECT;
! 351: chunkqueue_reset(con->write_queue);
! 352:
! 353: return HANDLER_FINISHED;
! 354: }
! 355:
! 356: chunkqueue_remove_finished_chunks(cq);
! 357:
! 358: if (dst_cq->bytes_in == (off_t)con->request.content_length) {
! 359: /* Content is ready */
! 360: con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
! 361: if (con->state == CON_STATE_READ_POST) {
! 362: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
! 363: }
! 364: return HANDLER_GO_ON;
! 365: } else if (is_closed) {
! 366: #if 0
! 367: con->http_status = 400; /* Bad Request */
! 368: con->keep_alive = 0;
! 369: con->mode = DIRECT;
! 370: chunkqueue_reset(con->write_queue);
! 371:
! 372: return HANDLER_FINISHED;
! 373: #endif
! 374: return HANDLER_ERROR;
! 375: } else {
! 376: con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
! 377: return (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)
! 378: ? HANDLER_GO_ON
! 379: : HANDLER_WAIT_FOR_EVENT;
! 380: }
! 381: }
! 382:
! 383: void connection_response_reset(server *srv, connection *con) {
! 384: UNUSED(srv);
! 385:
! 386: con->http_status = 0;
! 387: con->is_writable = 1;
! 388: con->file_finished = 0;
! 389: con->file_started = 0;
! 390: con->got_response = 0;
! 391: con->parsed_response = 0;
! 392: con->response.keep_alive = 0;
! 393: con->response.content_length = -1;
! 394: con->response.transfer_encoding = 0;
! 395: buffer_reset(con->physical.path);
! 396: array_reset(con->response.headers);
! 397: chunkqueue_reset(con->write_queue);
! 398: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>