It is blocked mode sample but work.
/* * Copyright 2004-2019 Oleg Borodin <borodin@unix7.org> */ #include <stdlib.h> #include <stdio.h> #include <stdbool.h> #include <pthread.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <openssl/ssl.h> #include <openssl/err.h> typedef struct queue { int *items; int front; int rear; int size; int maxsize; pthread_mutex_t mutex; } queue_t; queue_t *queue_create(int size) { queue_t *q = NULL; q = (queue_t *)malloc(sizeof(queue_t)); q->items = (int *)malloc(size * sizeof(int)); q->maxsize = size; q->front = 0; q->rear = -1; q->size = 0; return q; } int queue_size(queue_t *q) { pthread_mutex_lock(&q->mutex); int res = q->size; pthread_mutex_unlock(&q->mutex); return res; } int queue_front(queue_t *q) { int res = -1; pthread_mutex_lock(&q->mutex); if (q->size > 0) { res = q->items[q->front]; q->front = (q->front + 1) % q->maxsize; q->size--; } pthread_mutex_unlock(&q->mutex); return res; } bool queue_push(queue_t* q, int x) { bool res = false; pthread_mutex_lock(&q->mutex); if (q->size < q->maxsize) { q->rear = (q->rear + 1) % q->maxsize; q->items[q->rear] = x; q->size++; res = true; } pthread_mutex_unlock(&q->mutex); return res; } typedef struct thrpool { pthread_cond_t cond; pthread_mutex_t mutex; queue_t* queue; const int poolsize; pthread_t* threads; SSL_CTX *context; } thrpool_t; thrpool_t* thrpool_create(const int pool_size, const int queue_size, void* handler) { thrpool_t* tp = NULL; tp = (thrpool_t*)malloc(sizeof(thrpool_t)); tp->queue = queue_create(queue_size); tp->threads = (pthread_t*)malloc(sizeof(pthread_t) * pool_size); for (int i = 0; i < pool_size; i++) { pthread_create(&(tp->threads[i]), NULL, handler, (void*)tp); } for (int i = 0; i < pool_size; i++) { pthread_detach(tp->threads[i]); fprintf(stderr, "create thread %d\n", (int)tp->threads[i]); } return tp; } inline bool thrpool_enqueue(thrpool_t* tp, int newsock) { if (queue_push(tp->queue, newsock)) { pthread_mutex_unlock(&(tp->mutex)); pthread_cond_signal(&(tp->cond)); return true; } return false; } inline void thrpool_lock(thrpool_t* tp) { pthread_mutex_lock(&(tp->mutex)); } inline void thrpool_unlock(thrpool_t* tp) { pthread_mutex_unlock(&(tp->mutex)); } inline void thrpool_wait(thrpool_t* tp) { pthread_cond_wait(&(tp->cond), &(tp->mutex)); } void* handler(void* argp) { thrpool_t* tp = (thrpool_t*)argp; while(true) { thrpool_lock(tp); while(queue_size(tp->queue) == 0) { thrpool_wait(tp); } int sock = queue_front(tp->queue); SSL *ssl_sock = SSL_new(tp->context); SSL_set_fd(ssl_sock, sock); if (SSL_accept(ssl_sock) > 0) { char ibuffer[1024]; SSL_read(ssl_sock, ibuffer, 1024); //printf("worker %d handle socket %d\n", (int)pthread_self(), sock); char res[] = "HTTP/1.1 200 OK\r\n" "Accept-Ranges: bytes\r\n" "Content-Type: text/plain\r\n" "Content-Length: 0\r\n" "Conection: close\r\n" "Server: Srv11/0.1\r\n" "Date: Wed, 15 May 2019 20:05:07 UTC\r\n" "\r\n"; SSL_write(ssl_sock, res, strlen(res)); } SSL_free(ssl_sock); shutdown(sock, SHUT_RDWR); close(sock); thrpool_unlock(tp); } return NULL; } int main(int argc, char **argv) { const int poolsize = 10; const int queuesize = 1024 * 10; thrpool_t* tp = thrpool_create(poolsize, queuesize, handler); int sock; if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "cannot create socket, exit\n"); exit(1); } int optval = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { fprintf(stderr, "cannot set socket option, exit\n"); exit(1); } struct sockaddr addr; const int port = 1024; struct sockaddr_in* paddr = (struct sockaddr_in*)&addr; paddr->sin_family = AF_INET; paddr->sin_addr.s_addr = INADDR_ANY; paddr->sin_port = htons(port); paddr->sin_len = sizeof(struct sockaddr_in); if (bind(sock, (struct sockaddr*)paddr, paddr->sin_len) < 0) { fprintf(stderr, "cannot bind socket, exit\n"); exit(1); } if (listen(sock, 2048) < 0) { fprintf(stderr, "cannot listen socket, exit\n"); exit(1); } SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); //const SSL_METHOD *method = SSLv23_server_method(); const SSL_METHOD *method = TLSv1_2_server_method(); tp->context = SSL_CTX_new(method); if (!tp->context) { fprintf(stderr, "unable to create SSL context\n"); exit(1); } SSL_CTX_set_ecdh_auto(tp->context, 1); if (SSL_CTX_use_certificate_file(tp->context, "server.crt", SSL_FILETYPE_PEM) <= 0) { fprintf(stderr, "unable to read certificate file\n"); exit(1); } if (SSL_CTX_use_PrivateKey_file(tp->context, "server.key", SSL_FILETYPE_PEM) <= 0 ) { fprintf(stderr, "unable to read key file\n"); exit(1); } int newsock; thrpool_lock(tp); while ((newsock = accept(sock, NULL, 0)) > 0) { if (!thrpool_enqueue(tp, newsock)) { shutdown(sock, SHUT_RDWR); close(sock); } } return 0; }
$ ab -c 1000 -n10000 'https://localhost:1024/' This is ApacheBench, Version 2.3 <$Revision: 1826891 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking localhost (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: Srv11/0.1 Server Hostname: localhost Server Port: 1024 SSL/TLS Protocol: TLSv1.2,ECDHE-RSA-AES256-GCM-SHA384,2048,256 TLS Server Name: localhost Document Path: / Document Length: 0 bytes Concurrency Level: 1000 Time taken for tests: 19.100 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 1600000 bytes HTML transferred: 0 bytes Requests per second: 523.56 [#/sec] (mean) Time per request: 1909.999 [ms] (mean) Time per request: 1.910 [ms] (mean, across all concurrent requests) Transfer rate: 81.81 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 8 1824 568.1 1635 4184 Processing: 0 0 0.7 0 70 Waiting: 0 0 0.0 0 0 Total: 78 1824 568.1 1635 4184 Percentage of the requests served within a certain time (ms) 50% 1635 66% 1698 75% 1702 80% 1703 90% 2487 95% 3394 98% 3868 99% 4027 100% 4184 (longest request)