File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / network_openssl.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

    1: #include "first.h"
    2: 
    3: #include "network_backends.h"
    4: 
    5: #if defined(USE_OPENSSL)
    6: 
    7: #include "network.h"
    8: #include "log.h"
    9: 
   10: #include <unistd.h>
   11: #include <stdlib.h>
   12: 
   13: #include <errno.h>
   14: #include <string.h>
   15: 
   16: # include <openssl/ssl.h>
   17: # include <openssl/err.h>
   18: 
   19: static int load_next_chunk(server *srv, connection *con, chunkqueue *cq, off_t max_bytes, const char **data, size_t *data_len) {
   20: 	chunk * const c = cq->first;
   21: 
   22: #define LOCAL_SEND_BUFSIZE (64 * 1024)
   23: 	/* this is a 64k sendbuffer
   24: 	 *
   25: 	 * it has to stay at the same location all the time to satisfy the needs
   26: 	 * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
   27: 	 *
   28: 	 * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
   29: 	 * -> we expect a 64k block to 'leak' in valgrind
   30: 	 * */
   31: 	static char *local_send_buffer = NULL;
   32: 
   33: 	force_assert(NULL != c);
   34: 
   35: 	switch (c->type) {
   36: 	case MEM_CHUNK:
   37: 		{
   38: 			size_t have;
   39: 
   40: 			force_assert(c->offset >= 0 && c->offset <= (off_t)buffer_string_length(c->mem));
   41: 
   42: 			have = buffer_string_length(c->mem) - c->offset;
   43: 			if ((off_t) have > max_bytes) have = max_bytes;
   44: 
   45: 			*data = c->mem->ptr + c->offset;
   46: 			*data_len = have;
   47: 		}
   48: 		return 0;
   49: 
   50: 	case FILE_CHUNK:
   51: 		if (NULL == local_send_buffer) {
   52: 			local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
   53: 			force_assert(NULL != local_send_buffer);
   54: 		}
   55: 
   56: 		if (0 != network_open_file_chunk(srv, con, cq)) return -1;
   57: 
   58: 		{
   59: 			off_t offset, toSend;
   60: 
   61: 			force_assert(c->offset >= 0 && c->offset <= c->file.length);
   62: 			offset = c->file.start + c->offset;
   63: 			toSend = c->file.length - c->offset;
   64: 
   65: 			if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
   66: 			if (toSend > max_bytes) toSend = max_bytes;
   67: 
   68: 			if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
   69: 				log_error_write(srv, __FILE__, __LINE__, "ss", "lseek: ", strerror(errno));
   70: 				return -1;
   71: 			}
   72: 			if (-1 == (toSend = read(c->file.fd, local_send_buffer, toSend))) {
   73: 				log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
   74: 				return -1;
   75: 			}
   76: 
   77: 			*data = local_send_buffer;
   78: 			*data_len = toSend;
   79: 		}
   80: 		return 0;
   81: 	}
   82: 
   83: 	return -1;
   84: }
   85: 
   86: 
   87: int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) {
   88: 	/* the remote side closed the connection before without shutdown request
   89: 	 * - IE
   90: 	 * - wget
   91: 	 * if keep-alive is disabled */
   92: 
   93: 	if (con->keep_alive == 0) {
   94: 		SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
   95: 	}
   96: 
   97: 	chunkqueue_remove_finished_chunks(cq);
   98: 
   99: 	while (max_bytes > 0 && NULL != cq->first) {
  100: 		const char *data;
  101: 		size_t data_len;
  102: 		int r;
  103: 
  104: 		if (0 != load_next_chunk(srv, con, cq, max_bytes, &data, &data_len)) return -1;
  105: 
  106: 		/**
  107: 		 * SSL_write man-page
  108: 		 *
  109: 		 * WARNING
  110: 		 *        When an SSL_write() operation has to be repeated because of
  111: 		 *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
  112: 		 *        repeated with the same arguments.
  113: 		 */
  114: 
  115: 		ERR_clear_error();
  116: 		r = SSL_write(ssl, data, data_len);
  117: 
  118: 		if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
  119: 			log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
  120: 			return -1;
  121: 		}
  122: 
  123: 		if (r <= 0) {
  124: 			int ssl_r;
  125: 			unsigned long err;
  126: 
  127: 			switch ((ssl_r = SSL_get_error(ssl, r))) {
  128: 			case SSL_ERROR_WANT_READ:
  129: 				con->is_readable = -1;
  130: 				return 0; /* try again later */
  131: 			case SSL_ERROR_WANT_WRITE:
  132: 				con->is_writable = -1;
  133: 				return 0; /* try again later */
  134: 			case SSL_ERROR_SYSCALL:
  135: 				/* perhaps we have error waiting in our error-queue */
  136: 				if (0 != (err = ERR_get_error())) {
  137: 					do {
  138: 						log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
  139: 								ssl_r, r,
  140: 								ERR_error_string(err, NULL));
  141: 					} while((err = ERR_get_error()));
  142: 				} else if (r == -1) {
  143: 					/* no, but we have errno */
  144: 					switch(errno) {
  145: 					case EPIPE:
  146: 					case ECONNRESET:
  147: 						return -2;
  148: 					default:
  149: 						log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
  150: 								ssl_r, r, errno,
  151: 								strerror(errno));
  152: 						break;
  153: 					}
  154: 				} else {
  155: 					/* neither error-queue nor errno ? */
  156: 					log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
  157: 							ssl_r, r, errno,
  158: 							strerror(errno));
  159: 				}
  160: 				break;
  161: 
  162: 			case SSL_ERROR_ZERO_RETURN:
  163: 				/* clean shutdown on the remote side */
  164: 
  165: 				if (r == 0) return -2;
  166: 
  167: 				/* fall through */
  168: 			default:
  169: 				while((err = ERR_get_error())) {
  170: 					log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
  171: 							ssl_r, r,
  172: 							ERR_error_string(err, NULL));
  173: 				}
  174: 				break;
  175: 			}
  176: 			return -1;
  177: 		}
  178: 
  179: 		chunkqueue_mark_written(cq, r);
  180: 		max_bytes -= r;
  181: 
  182: 		if ((size_t) r < data_len) break; /* try again later */
  183: 	}
  184: 
  185: 	return 0;
  186: }
  187: #endif /* USE_OPENSSL */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>