Annotation of embedaddon/lighttpd/src/network_openssl.c, revision 1.1
1.1 ! misho 1: #include "network_backends.h"
! 2:
! 3: #ifdef USE_OPENSSL
! 4:
! 5: #include "network.h"
! 6: #include "fdevent.h"
! 7: #include "log.h"
! 8: #include "stat_cache.h"
! 9:
! 10: #include <sys/types.h>
! 11: #include <sys/socket.h>
! 12: #include <sys/stat.h>
! 13: #include <sys/time.h>
! 14: #include <sys/resource.h>
! 15:
! 16: #include <netinet/in.h>
! 17: #include <netinet/tcp.h>
! 18:
! 19: #include <errno.h>
! 20: #include <fcntl.h>
! 21: #include <unistd.h>
! 22: #include <netdb.h>
! 23: #include <string.h>
! 24: #include <stdlib.h>
! 25: #include <assert.h>
! 26:
! 27: # include <openssl/ssl.h>
! 28: # include <openssl/err.h>
! 29:
! 30: int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) {
! 31: int ssl_r;
! 32: chunk *c;
! 33:
! 34: /* this is a 64k sendbuffer
! 35: *
! 36: * it has to stay at the same location all the time to satisfy the needs
! 37: * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
! 38: *
! 39: * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
! 40: * -> we expect a 64k block to 'leak' in valgrind
! 41: *
! 42: *
! 43: * In reality we would like to use mmap() but we don't have a guarantee that
! 44: * we get the same mmap() address for each call. On openbsd the mmap() address
! 45: * even randomized.
! 46: * That means either we keep the mmap() open or we do a read() into a
! 47: * constant buffer
! 48: * */
! 49: #define LOCAL_SEND_BUFSIZE (64 * 1024)
! 50: static char *local_send_buffer = NULL;
! 51:
! 52: /* the remote side closed the connection before without shutdown request
! 53: * - IE
! 54: * - wget
! 55: * if keep-alive is disabled */
! 56:
! 57: if (con->keep_alive == 0) {
! 58: SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
! 59: }
! 60:
! 61: for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {
! 62: int chunk_finished = 0;
! 63:
! 64: switch(c->type) {
! 65: case MEM_CHUNK: {
! 66: char * offset;
! 67: off_t toSend;
! 68: ssize_t r;
! 69:
! 70: if (c->mem->used == 0 || c->mem->used == 1) {
! 71: chunk_finished = 1;
! 72: break;
! 73: }
! 74:
! 75: offset = c->mem->ptr + c->offset;
! 76: toSend = c->mem->used - 1 - c->offset;
! 77: if (toSend > max_bytes) toSend = max_bytes;
! 78:
! 79: /**
! 80: * SSL_write man-page
! 81: *
! 82: * WARNING
! 83: * When an SSL_write() operation has to be repeated because of
! 84: * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
! 85: * repeated with the same arguments.
! 86: *
! 87: */
! 88:
! 89: ERR_clear_error();
! 90: r = SSL_write(ssl, offset, toSend);
! 91:
! 92: if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
! 93: log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
! 94: return -1;
! 95: }
! 96:
! 97: if (r <= 0) {
! 98: unsigned long err;
! 99:
! 100: switch ((ssl_r = SSL_get_error(ssl, r))) {
! 101: case SSL_ERROR_WANT_WRITE:
! 102: break;
! 103: case SSL_ERROR_SYSCALL:
! 104: /* perhaps we have error waiting in our error-queue */
! 105: if (0 != (err = ERR_get_error())) {
! 106: do {
! 107: log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
! 108: ssl_r, r,
! 109: ERR_error_string(err, NULL));
! 110: } while((err = ERR_get_error()));
! 111: } else if (r == -1) {
! 112: /* no, but we have errno */
! 113: switch(errno) {
! 114: case EPIPE:
! 115: case ECONNRESET:
! 116: return -2;
! 117: default:
! 118: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
! 119: ssl_r, r, errno,
! 120: strerror(errno));
! 121: break;
! 122: }
! 123: } else {
! 124: /* neither error-queue nor errno ? */
! 125: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
! 126: ssl_r, r, errno,
! 127: strerror(errno));
! 128: }
! 129:
! 130: return -1;
! 131: case SSL_ERROR_ZERO_RETURN:
! 132: /* clean shutdown on the remote side */
! 133:
! 134: if (r == 0) return -2;
! 135:
! 136: /* fall through */
! 137: default:
! 138: while((err = ERR_get_error())) {
! 139: log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
! 140: ssl_r, r,
! 141: ERR_error_string(err, NULL));
! 142: }
! 143:
! 144: return -1;
! 145: }
! 146: } else {
! 147: c->offset += r;
! 148: cq->bytes_out += r;
! 149: max_bytes -= r;
! 150: }
! 151:
! 152: if (c->offset == (off_t)c->mem->used - 1) {
! 153: chunk_finished = 1;
! 154: }
! 155:
! 156: break;
! 157: }
! 158: case FILE_CHUNK: {
! 159: char *s;
! 160: ssize_t r;
! 161: stat_cache_entry *sce = NULL;
! 162: int ifd;
! 163: int write_wait = 0;
! 164:
! 165: if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
! 166: log_error_write(srv, __FILE__, __LINE__, "sb",
! 167: strerror(errno), c->file.name);
! 168: return -1;
! 169: }
! 170:
! 171: if (NULL == local_send_buffer) {
! 172: local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
! 173: assert(local_send_buffer);
! 174: }
! 175:
! 176: do {
! 177: off_t offset = c->file.start + c->offset;
! 178: off_t toSend = c->file.length - c->offset;
! 179: if (toSend > max_bytes) toSend = max_bytes;
! 180:
! 181: if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
! 182:
! 183: if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
! 184: log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
! 185:
! 186: return -1;
! 187: }
! 188:
! 189:
! 190: lseek(ifd, offset, SEEK_SET);
! 191: if (-1 == (toSend = read(ifd, local_send_buffer, toSend))) {
! 192: close(ifd);
! 193: log_error_write(srv, __FILE__, __LINE__, "ss", "read failed:", strerror(errno));
! 194: return -1;
! 195: }
! 196:
! 197: s = local_send_buffer;
! 198:
! 199: close(ifd);
! 200:
! 201: ERR_clear_error();
! 202: r = SSL_write(ssl, s, toSend);
! 203:
! 204: if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
! 205: log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
! 206: return -1;
! 207: }
! 208:
! 209: if (r <= 0) {
! 210: unsigned long err;
! 211:
! 212: switch ((ssl_r = SSL_get_error(ssl, r))) {
! 213: case SSL_ERROR_WANT_WRITE:
! 214: write_wait = 1;
! 215: break;
! 216: case SSL_ERROR_SYSCALL:
! 217: /* perhaps we have error waiting in our error-queue */
! 218: if (0 != (err = ERR_get_error())) {
! 219: do {
! 220: log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
! 221: ssl_r, r,
! 222: ERR_error_string(err, NULL));
! 223: } while((err = ERR_get_error()));
! 224: } else if (r == -1) {
! 225: /* no, but we have errno */
! 226: switch(errno) {
! 227: case EPIPE:
! 228: case ECONNRESET:
! 229: return -2;
! 230: default:
! 231: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
! 232: ssl_r, r, errno,
! 233: strerror(errno));
! 234: break;
! 235: }
! 236: } else {
! 237: /* neither error-queue nor errno ? */
! 238: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
! 239: ssl_r, r, errno,
! 240: strerror(errno));
! 241: }
! 242:
! 243: return -1;
! 244: case SSL_ERROR_ZERO_RETURN:
! 245: /* clean shutdown on the remote side */
! 246:
! 247: if (r == 0) return -2;
! 248:
! 249: /* fall thourgh */
! 250: default:
! 251: while((err = ERR_get_error())) {
! 252: log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
! 253: ssl_r, r,
! 254: ERR_error_string(err, NULL));
! 255: }
! 256:
! 257: return -1;
! 258: }
! 259: } else {
! 260: c->offset += r;
! 261: cq->bytes_out += r;
! 262: max_bytes -= r;
! 263: }
! 264:
! 265: if (c->offset == c->file.length) {
! 266: chunk_finished = 1;
! 267: }
! 268: } while (!chunk_finished && !write_wait && max_bytes > 0);
! 269:
! 270: break;
! 271: }
! 272: default:
! 273: log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
! 274:
! 275: return -1;
! 276: }
! 277:
! 278: if (!chunk_finished) {
! 279: /* not finished yet */
! 280:
! 281: break;
! 282: }
! 283: }
! 284:
! 285: return 0;
! 286: }
! 287: #endif
! 288:
! 289: #if 0
! 290: network_openssl_init(void) {
! 291: p->write_ssl = network_openssl_write_chunkset;
! 292: }
! 293: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>