Tomato 1.28
[tomato.git] / release / src / router / matrixssl / examples / httpsReflector.c
blob4a901dfcbf535fcec0662a4e4d4f7c65cdaba41f
1 /*
2 * httpReflector.c
3 * Release $Name: MATRIXSSL_1_8_8_OPEN $
5 * Simple example program for MatrixSSL
6 * Accepts a HTTPS request and echos the response back to the sender.
7 */
8 /*
9 * Copyright (c) PeerSec Networks, 2002-2009. All Rights Reserved.
10 * The latest version of this code is available at http://www.matrixssl.org
12 * This software is open source; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This General Public License does NOT permit incorporating this software
18 * into proprietary programs. If you are unable to comply with the GPL, a
19 * commercial license for this software may be purchased from PeerSec Networks
20 * at http://www.peersec.com
22 * This program is distributed in WITHOUT ANY WARRANTY; without even the
23 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 * See the GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * http://www.gnu.org/copyleft/gpl.html
31 /******************************************************************************/
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
37 /******************************************************************************/
39 #include "sslSocket.h"
41 #define HTTPS_PORT 4433
42 static char keyfile[] = "privkeySrv.pem";
43 static char certfile[] = "certSrv.pem";
45 static const char responseHdr[] = "HTTP/1.0 200 OK\r\n"
46 "Server: PeerSec Networks MatrixSSL\r\n"
47 "Pragma: no-cache\r\n"
48 "Cache-Control: no-cache\r\n"
49 "Content-type: text/plain\r\n"
50 "\r\n"
51 "PeerSec Networks\n"
52 "Successful MatrixSSL request:\n";
54 static const char quitString[] = "GET /quit";
55 static const char againString[] = "GET /again";
59 /******************************************************************************/
61 Helper framework for testing matrixSslReadKeysMem
63 #define USE_MEM_CERTS 0
64 #if USE_MEM_CERTS
65 #include <sys/stat.h>
66 static int32 getFileBin(char *fileName, unsigned char **bin, int32 *binLen);
67 #endif
69 /******************************************************************************/
71 This example application acts as an https server that accepts incoming
72 client requests and reflects incoming data back to that client.
74 #if VXWORKS
75 int _httpsReflector(char *arg1)
76 #elif WINCE
77 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
78 LPWSTR lpCmdLine, int nCmdShow)
79 #else
80 int main(int argc, char **argv)
81 #endif
83 sslConn_t *cp;
84 sslKeys_t *keys;
85 SOCKET listenfd, fd;
86 WSADATA wsaData;
87 unsigned char buf[1024];
88 unsigned char *response, *c;
89 int responseHdrLen, acceptAgain, flags;
90 int bytes, status, quit, again, rc, err;
91 #if USE_MEM_CERTS
92 unsigned char *servBin, *servKeyBin, *caBin;
93 int servBinLen, caBinLen, servKeyBinLen;
94 #endif
96 cp = NULL;
98 Initialize Windows sockets (no-op on other platforms)
100 WSAStartup(MAKEWORD(1,1), &wsaData);
102 Initialize the MatrixSSL Library, and read in the public key (certificate)
103 and private key.
105 if (matrixSslOpen() < 0) {
106 fprintf(stderr, "matrixSslOpen failed, exiting...");
109 #if USE_MEM_CERTS
111 Example of DER binary certs for matrixSslReadKeysMem
113 getFileBin("certSrv.der", &servBin, &servBinLen);
114 getFileBin("privkeySrv.der", &servKeyBin, &servKeyBinLen);
115 getFileBin("CAcertCln.der", &caBin, &caBinLen);
117 matrixSslReadKeysMem(&keys, servBin, servBinLen,
118 servKeyBin, servKeyBinLen, caBin, caBinLen);
120 free(servBin);
121 free(servKeyBin);
122 free(caBin);
123 #else
125 Standard PEM files
127 if (matrixSslReadKeys(&keys, certfile, keyfile, NULL, NULL) < 0) {
128 fprintf(stderr, "Error reading or parsing %s or %s.\n",
129 certfile, keyfile);
130 goto promptAndExit;
132 #endif /* USE_MEM_CERTS */
133 fprintf(stdout,
134 "Run httpsClient or type https://127.0.0.1:%d into your local Web browser.\n",
135 HTTPS_PORT);
137 Create the listen socket
139 if ((listenfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) {
140 fprintf(stderr, "Cannot listen on port %d\n", HTTPS_PORT);
141 goto promptAndExit;
144 Set blocking or not on the listen socket
146 setSocketBlock(listenfd);
148 Loop control initalization
150 quit = 0;
151 again = 0;
152 flags = 0;
154 acceptAgain = 1;
156 Main connection loop
158 while (!quit) {
160 if (acceptAgain) {
162 sslAccept creates a new server session
164 /* TODO - deadlock on blocking socket accept. Should disable blocking here */
165 if ((fd = socketAccept(listenfd, &err)) == INVALID_SOCKET) {
166 fprintf(stdout, "Error accepting connection: %d\n", err);
167 continue;
169 if ((rc = sslAccept(&cp, fd, keys, NULL, flags)) != 0) {
170 socketShutdown(fd);
171 continue;
174 flags = 0;
175 acceptAgain = 0;
178 Read response
179 < 0 return indicates an error.
180 0 return indicates an EOF or CLOSE_NOTIFY in this situation
181 > 0 indicates that some bytes were read. Keep reading until we see
182 the /r/n/r/n from the GET request. We don't actually parse the request,
183 we just echo it back.
185 c = buf;
186 readMore:
187 if ((rc = sslRead(cp, c, sizeof(buf) - (int)(c - buf), &status)) > 0) {
188 c += rc;
189 if (c - buf < 4 || memcmp(c - 4, "\r\n\r\n", 4) != 0) {
190 goto readMore;
192 } else {
193 if (rc < 0) {
194 fprintf(stdout, "sslRead error. dropping connection.\n");
196 if (rc < 0 || status == SSLSOCKET_EOF ||
197 status == SSLSOCKET_CLOSE_NOTIFY) {
198 socketShutdown(cp->fd);
199 sslFreeConnection(&cp);
200 acceptAgain = 1;
201 continue;
203 goto readMore;
206 Done reading. If the incoming data starts with the quitString,
207 quit the application after this request
209 if (memcmp(buf, quitString, min(c - buf,
210 (int)strlen(quitString))) == 0) {
211 quit++;
212 fprintf(stdout, "Q");
215 If the incoming data starts with the againString,
216 we are getting a pipeline request on the same session. Don't
217 close and wait for new connection in this case.
219 if (memcmp(buf, againString,
220 min(c - buf, (int)strlen(againString))) == 0) {
221 again++;
222 fprintf(stdout, "A");
223 } else {
224 fprintf(stdout, "R");
225 again = 0;
228 Copy the canned response header and decoded data from socket as the
229 response (reflector)
231 responseHdrLen = (int)strlen(responseHdr);
232 bytes = responseHdrLen + (int)(c - buf);
233 response = malloc(bytes);
234 memcpy(response, responseHdr, responseHdrLen);
235 memcpy(response + responseHdrLen, buf, c - buf);
237 Send response.
238 < 0 return indicates an error.
239 0 return indicates not all data was sent and we must retry
240 > 0 indicates that all requested bytes were sent
242 writeMore:
243 rc = sslWrite(cp, response, bytes, &status);
244 if (rc < 0) {
245 free(response);
246 fprintf(stdout, "Internal sslWrite error\n");
247 socketShutdown(cp->fd);
248 sslFreeConnection(&cp);
249 continue;
250 } else if (rc == 0) {
251 goto writeMore;
253 free(response);
255 If we saw an /again request, loop up and process another pipelined
256 HTTP request. The /again request is supported in the httpsClient
257 example code.
259 if (again) {
260 continue;
263 Send a closure alert for clean shutdown of remote SSL connection
264 This is for good form, some implementations just close the socket
266 sslWriteClosureAlert(cp);
268 Close the socket and wait for next connection (new session)
270 socketShutdown(cp->fd);
271 sslFreeConnection(&cp);
272 acceptAgain = 1;
275 Close listening socket, free remaining items
277 if (cp && cp->ssl) {
278 socketShutdown(cp->fd);
279 sslFreeConnection(&cp);
281 socketShutdown(listenfd);
283 matrixSslFreeKeys(keys);
284 matrixSslClose();
285 WSACleanup();
286 promptAndExit:
287 fprintf(stdout, "\n\nPress return to exit...\n");
288 getchar();
289 return 0;
294 #if USE_MEM_CERTS
295 static int32 getFileBin(char *fileName, unsigned char **bin,
296 int32 *binLen)
298 FILE *fp;
299 struct stat fstat;
300 size_t tmp = 0;
302 *binLen = 0;
303 *bin = NULL;
305 if (fileName == NULL) {
306 return -1;
308 if ((stat(fileName, &fstat) != 0) || (fp = fopen(fileName, "rb")) == NULL) {
309 return -7; /* FILE_NOT_FOUND */
312 *bin = malloc(fstat.st_size);
313 if (*bin == NULL) {
314 return -8; /* SSL_MEM_ERROR */
316 while (((tmp = fread(*bin + *binLen, sizeof(char), 512, fp)) > 0) &&
317 (*binLen < fstat.st_size)) {
318 *binLen += (int32)tmp;
320 fclose(fp);
321 return 0;
323 #endif
325 /******************************************************************************/