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