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>