It is blocked mode sample but work.
/* * Author, Copyright: Oleg Borodin <onborodin@gmail.com> */ #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)