1 /** @file
2
3 SSL delay test server
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22
23 */
24
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netdb.h>
28 #include <cstdio>
29 #include <cstdlib>
30 #include <unistd.h>
31 #include <cstring>
32 #include <openssl/ssl.h>
33 #include <fcntl.h>
34 #include <netinet/tcp.h>
35 #include <netinet/in.h>
36 #include <sys/socket.h>
37 #include <pthread.h>
38 #include <openssl/err.h>
39 #include <sys/time.h>
40 #include <sys/select.h>
41 #include <cerrno>
42
43 char req_buf[10000];
44 char post_buf[1000];
45
46 SSL_CTX *svr_ctx;
47 int connect_delay;
48 int ttfb_delay;
49
50 pthread_mutex_t *mutex_buf = nullptr;
51
52 struct thread_info {
53 struct addrinfo *result, *rp;
54 SSL_SESSION *session;
55 };
56
57 void
SSL_locking_callback(int mode,int type,const char * file,int line)58 SSL_locking_callback(int mode, int type, const char *file, int line)
59 {
60 if (mode & CRYPTO_LOCK) {
61 pthread_mutex_lock(&mutex_buf[type]);
62 } else if (mode & CRYPTO_UNLOCK) {
63 pthread_mutex_unlock(&mutex_buf[type]);
64 } else {
65 printf("invalid SSL locking mode 0x%x\n", mode);
66 }
67 }
68
69 void
SSL_pthreads_thread_id(CRYPTO_THREADID * id)70 SSL_pthreads_thread_id(CRYPTO_THREADID *id)
71 {
72 CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self());
73 }
74
75 char input_buf[1000];
76 char response_buf[] = "200 HTTP/1.1\r\nConnection: close\r\n\r\n";
77
78 void *
run_session(void * arg)79 run_session(void *arg)
80 {
81 int sfd = (intptr_t)arg;
82 SSL *ssl = SSL_new(svr_ctx);
83 if (ssl == nullptr) {
84 fprintf(stderr, "Failed to create ssl\n");
85 return nullptr;
86 }
87
88 #if OPENSSL_VERSION_NUMBER >= 0x10100000
89 SSL_set_max_proto_version(ssl, TLS1_2_VERSION);
90 #endif
91
92 SSL_set_fd(ssl, sfd);
93
94 fprintf(stderr, "Accept try %d\n", sfd);
95
96 // Potentially delay before processing the TLS handshake
97 if (connect_delay > 0) {
98 fprintf(stderr, "Connect delay %d\n", connect_delay);
99 // Delay here
100 sleep(connect_delay);
101 }
102 int did_accept = 0;
103
104 int ret = SSL_accept(ssl);
105
106 if (!did_accept && ret == 1) {
107 did_accept = 1;
108 fprintf(stderr, "Done accept\n");
109 } else {
110 int ssl_err = SSL_get_error(ssl, ret);
111 fprintf(stderr, "Failed accept ssl_error=%d errno=%d\n", ssl_err, errno);
112 return nullptr;
113 }
114
115 if (did_accept) {
116 ret = SSL_read(ssl, input_buf, sizeof(input_buf));
117 if (ret < 0) {
118 // Failure
119 fprintf(stderr, "Server read failure\n");
120 } else {
121 fprintf(stderr, "TTFB delay\n");
122 if (ttfb_delay > 0) {
123 // TTFB delay
124 sleep(ttfb_delay);
125 }
126 fprintf(stderr, "Write response\n");
127 ret = SSL_write(ssl, response_buf, strlen(response_buf));
128 fprintf(stderr, "Write response %d\n", ret);
129 if (ret <= 0) {
130 fprintf(stderr, "Server write failure\n");
131 } else {
132 fprintf(stderr, "Write response succeeded. Go to the next one\n");
133 }
134 }
135 }
136 if (ssl) {
137 SSL_free(ssl);
138 }
139 close(sfd);
140
141 return nullptr;
142 }
143
144 /**
145 * Simple TLS server with configurable delays
146 */
147 int
main(int argc,char * argv[])148 main(int argc, char *argv[])
149 {
150 int sfd;
151
152 if (argc != 5) {
153 fprintf(stderr, "Usage: %s <listen port> <handshake delay> <ttfb delay> <cert/key pem file>\n", argv[0]);
154 exit(EXIT_FAILURE);
155 }
156 short listen_port = atoi(argv[1]);
157 connect_delay = atoi(argv[2]);
158 ttfb_delay = atoi(argv[3]);
159 const char *pem_file = argv[4];
160
161 fprintf(stderr, "Listen on %d connect delay=%d ttfb delay=%d\n", listen_port, connect_delay, ttfb_delay);
162
163 int listenfd = socket(AF_INET, SOCK_STREAM, 0);
164 struct sockaddr_in serv_addr;
165
166 memset(&serv_addr, '0', sizeof(serv_addr));
167
168 serv_addr.sin_family = AF_INET;
169 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
170 serv_addr.sin_port = htons(listen_port);
171
172 bind(listenfd, reinterpret_cast<struct sockaddr *>(&serv_addr), sizeof(serv_addr));
173
174 SSL_load_error_strings();
175 SSL_library_init();
176
177 mutex_buf = static_cast<pthread_mutex_t *>(OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)));
178 for (int i = 0; i < CRYPTO_num_locks(); i++) {
179 pthread_mutex_init(&mutex_buf[i], nullptr);
180 }
181
182 CRYPTO_set_locking_callback(SSL_locking_callback);
183 #if CRYPTO_THREADID_set_callback
184 CRYPTO_THREADID_set_callback(SSL_pthreads_thread_id);
185 #endif
186
187 svr_ctx = SSL_CTX_new(SSLv23_server_method());
188 // Associate cert and key
189 if (SSL_CTX_use_certificate_file(svr_ctx, pem_file, SSL_FILETYPE_PEM) != 1) {
190 printf("Failed to load certificate from %s\n", pem_file);
191 exit(1);
192 }
193
194 if (SSL_CTX_use_PrivateKey_file(svr_ctx, pem_file, SSL_FILETYPE_PEM) != 1) {
195 printf("Failed to load private key from %s\n", pem_file);
196 exit(1);
197 }
198
199 listen(listenfd, 10);
200
201 for (;;) {
202 sfd = accept(listenfd, (struct sockaddr *)nullptr, nullptr);
203 if (sfd <= 0) {
204 // Failure
205 printf("Listen failure\n");
206 exit(1);
207 }
208
209 fprintf(stderr, "Spawn off new sesson thread %d\n", sfd);
210
211 // Spawn off new thread
212 pthread_t thread_id;
213 pthread_create(&thread_id, nullptr, run_session, (void *)(static_cast<intptr_t>(sfd)));
214 }
215
216 exit(0);
217 }
218