1 /*
2  *	server.c
3  *  Release $Name: MATRIXSSL-3-3-0-OPEN $
4  *
5  *	Non-blocking MatrixSSL server example supporting multiple connections
6  */
7 /*
8  *	Copyright (c) AuthenTec, Inc. 2011-2012
9  *	Copyright (c) PeerSec Networks, 2002-2011
10  *	All Rights Reserved
11  *
12  *	The latest version of this code is available at http://www.matrixssl.org
13  *
14  *	This software is open source; you can redistribute it and/or modify
15  *	it under the terms of the GNU General Public License as published by
16  *	the Free Software Foundation; either version 2 of the License, or
17  *	(at your option) any later version.
18  *
19  *	This General Public License does NOT permit incorporating this software
20  *	into proprietary programs.  If you are unable to comply with the GPL, a
21  *	commercial license for this software may be purchased from AuthenTec at
22  *	http://www.authentec.com/Products/EmbeddedSecurity/SecurityToolkits.aspx
23  *
24  *	This program is distributed in WITHOUT ANY WARRANTY; without even the
25  *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26  *	See the GNU General Public License for more details.
27  *
28  *	You should have received a copy of the GNU General Public License
29  *	along with this program; if not, write to the Free Software
30  *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31  *	http://www.gnu.org/copyleft/gpl.html
32  */
33 /******************************************************************************/
34 
35 #include "app.h"
36 #include "matrixssl/matrixsslApi.h"
37 
38 #ifdef USE_SERVER_SIDE_SSL
39 
40 #include <signal.h>         /* Defines SIGTERM, etc. */
41 
42 #ifdef WIN32
43 #pragma message("DO NOT USE THESE DEFAULT KEYS IN PRODUCTION ENVIRONMENTS.")
44 #else
45 #warning "DO NOT USE THESE DEFAULT KEYS IN PRODUCTION ENVIRONMENTS."
46 #endif
47 
48 
49 #define USE_HEADER_KEYS
50 
51 #ifdef USE_HEADER_KEYS
52 #include "sampleCerts/certSrv.h"
53 #include "sampleCerts/privkeySrv.h"
54 #else
55 static char certSrvFile[] = "certSrv.pem";
56 static char privkeySrvFile[] = "privkeySrv.pem";
57 #endif /* USE_HEADER_KEYS */
58 
59 
60 /********************************** Defines ***********************************/
61 
62 #define SSL_TIMEOUT			45000
63 #define SELECT_TIME			1000
64 
65 #define	GOTO_SANITY			32	/* Must be <= 255 */
66 /*
67 	The ACCEPT_QUEUE is an optimization mechanism that allows the server to
68 	accept() up to this many connections before serving any of them.  The
69 	reason is that the timeout waiting for the accept() is much shorter
70 	than the timeout for the actual processing.
71 */
72 #define	ACCEPT_QUEUE		16
73 
74 /********************************** Globals ***********************************/
75 
76 static DLListEntry		g_conns;
77 static int32			g_exitFlag;
78 static unsigned char	g_httpResponseHdr[] = "HTTP/1.0 200 OK\r\n"
79 	"Server: AuthenTec MatrixSSL/" MATRIXSSL_VERSION "\r\n"
80 	"Pragma: no-cache\r\n"
81 	"Cache-Control: no-cache\r\n"
82 	"Content-type: text/plain\r\n"
83 	"Content-length: 9\r\n"
84 	"\r\n"
85 	"MatrixSSL";
86 
87 
88 /****************************** Local Functions *******************************/
89 
90 static int32 selectLoop(sslKeys_t *keys, SOCKET lfd);
91 static int32 httpWriteResponse(ssl_t *cp);
92 static void setSocketOptions(SOCKET fd);
93 static SOCKET socketListen(short port, int32 *err);
94 static void closeConn(httpConn_t *cp, int32 reason);
95 
96 #ifdef POSIX
97 static void sigsegv_handler(int i);
98 static void sigintterm_handler(int i);
99 static int32 sighandlers(void);
100 #endif /* POSIX */
101 
102 
103 #define certCb NULL
104 
105 /******************************************************************************/
106 /*
107 	Non-blocking socket event handler
108 	Wait one time in select for events on any socket
109 	This will accept new connections, read and write to sockets that are
110 	connected, and close sockets as required.
111  */
selectLoop(sslKeys_t * keys,SOCKET lfd)112 static int32 selectLoop(sslKeys_t *keys, SOCKET lfd)
113 {
114 	httpConn_t		*cp;
115 	psTime_t		now;
116 	DLListEntry		connsTmp;
117 	DLListEntry		*pList;
118 
119 	fd_set			readfd, writefd;
120 	struct timeval	timeout;
121 	SOCKET			fd, maxfd;
122 
123 	unsigned char	*buf;
124 	int32			rc, len, transferred, val;
125 	unsigned char	rSanity, wSanity, acceptSanity;
126 
127 	DLListInit(&connsTmp);
128 	rc = PS_SUCCESS;
129 	maxfd = INVALID_SOCKET;
130 	timeout.tv_sec = SELECT_TIME / 1000;
131 	timeout.tv_usec = (SELECT_TIME % 1000) * 1000;
132 	FD_ZERO(&readfd);
133 	FD_ZERO(&writefd);
134 
135 	/* Always set readfd for listening socket */
136 	FD_SET(lfd, &readfd);
137 	if (lfd > maxfd) {
138 		maxfd = lfd;
139 	}
140 /*
141 	Check timeouts and set readfd and writefd for connections as required.
142 	We use connsTemp so that removal on error from the active iteration list
143 		doesn't interfere with list traversal
144  */
145 	psGetTime(&now);
146 	while (!DLListIsEmpty(&g_conns)) {
147 		pList = DLListGetHead(&g_conns);
148 		cp = DLListGetContainer(pList, httpConn_t, List);
149 		DLListInsertTail(&connsTmp, &cp->List);
150 		/*	If timeout != 0 msec ith no new data, close */
151 		if (cp->timeout && (psDiffMsecs(cp->time, now) > (int32)cp->timeout)) {
152 			closeConn(cp, PS_TIMEOUT_FAIL);
153 			continue;	/* Next connection */
154 		}
155 		/* Always select for read */
156 		FD_SET(cp->fd, &readfd);
157 		/* Select for write if there's pending write data or connection */
158 		if (matrixSslGetOutdata(cp->ssl, NULL) > 0) {
159 			FD_SET(cp->fd, &writefd);
160 		}
161 		/* Housekeeping for maxsock in select call */
162 		if (cp->fd > maxfd) {
163 			maxfd = cp->fd;
164 		}
165 	}
166 
167 	/* Use select to check for events on the sockets */
168 	if ((val = select(maxfd + 1, &readfd, &writefd, NULL, &timeout)) <= 0) {
169 		/* On error, restore global connections list */
170 		while (!DLListIsEmpty(&connsTmp)) {
171 			pList = DLListGetHead(&connsTmp);
172 			cp = DLListGetContainer(pList, httpConn_t, List);
173 			DLListInsertTail(&g_conns, &cp->List);
174 		}
175 		/* Select timeout */
176 		if (val == 0) {
177 			return PS_TIMEOUT_FAIL;
178 		}
179 		/* Woke due to interrupt */
180 		if (SOCKET_ERRNO == EINTR) {
181 			return PS_TIMEOUT_FAIL;
182 		}
183 		/* Should attempt to handle more errnos, such as EBADF */
184 		return PS_PLATFORM_FAIL;
185 	}
186 
187 	/* Check listener for new incoming socket connections */
188 	if (FD_ISSET(lfd, &readfd)) {
189 		for (acceptSanity = 0; acceptSanity < ACCEPT_QUEUE; acceptSanity++) {
190 			fd = accept(lfd, NULL, NULL);
191 			if (fd == INVALID_SOCKET) {
192 				break;	/* Nothing more to accept; next listener */
193 			}
194 			setSocketOptions(fd);
195 			cp = malloc(sizeof(httpConn_t));
196 			if ((rc = matrixSslNewServerSession(&cp->ssl, keys, certCb)) < 0) {
197 				close(fd); fd = INVALID_SOCKET;
198 				continue;
199 			}
200 			cp->fd = fd;
201 			fd = INVALID_SOCKET;
202 			cp->timeout = SSL_TIMEOUT;
203 			psGetTime(&cp->time);
204 			cp->parsebuf = NULL;
205 			cp->parsebuflen = 0;
206 			DLListInsertTail(&connsTmp, &cp->List);
207 			/* Fake that there is read data available, no harm if there isn't */
208 			FD_SET(cp->fd, &readfd);
209 /*			_psTraceInt("=== New Client %d ===\n", cp->fd); */
210 		}
211 	}
212 
213 	/* Check each connection for read/write activity */
214 	while (!DLListIsEmpty(&connsTmp)) {
215 		pList = DLListGetHead(&connsTmp);
216 		cp = DLListGetContainer(pList, httpConn_t, List);
217 		DLListInsertTail(&g_conns, &cp->List);
218 
219 		rSanity = wSanity = 0;
220 /*
221 		See if there's pending data to send on this connection
222 		We could use FD_ISSET, but this is more reliable for the current
223 			state of data to send.
224  */
225 WRITE_MORE:
226 		if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) {
227 			/* Could get a EWOULDBLOCK since we don't check FD_ISSET */
228 			transferred = send(cp->fd, buf, len, MSG_DONTWAIT);
229 			if (transferred <= 0) {
230 #ifdef WIN32
231 				if (SOCKET_ERRNO != EWOULDBLOCK &&
232 					SOCKET_ERRNO != WSAEWOULDBLOCK) {
233 
234 #else
235 				if (SOCKET_ERRNO != EWOULDBLOCK) {
236 #endif
237 					closeConn(cp, PS_PLATFORM_FAIL);
238 					continue;	/* Next connection */
239 				}
240 			} else {
241 				/* Indicate that we've written > 0 bytes of data */
242 				if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) {
243 					closeConn(cp, PS_ARG_FAIL);
244 					continue;	/* Next connection */
245 				}
246 				if (rc == MATRIXSSL_REQUEST_CLOSE) {
247 					closeConn(cp, MATRIXSSL_REQUEST_CLOSE);
248 					continue;	/* Next connection */
249 				} else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
250 					/* If the protocol is server initiated, send data here */
251 #ifdef ENABLE_FALSE_START
252 					/* OR this could be a Chrome browser using
253 						FALSE_START and the application data is already
254 						waiting in our inbuf for processing */
255 					if ((rc = matrixSslReceivedData(cp->ssl, 0,
256 								&buf, (uint32*)&len)) < 0) {
257 							closeConn(cp, 0);
258 							continue;	/* Next connection */
259 					}
260 					if (rc > 0) { /* There was leftover data */
261 						goto PROCESS_MORE;
262 					}
263 #endif /* ENABLE_FALSE_START  */
264 
265 				}
266 				/* Update activity time */
267 				psGetTime(&cp->time);
268 				/* Try to send again if more data to send */
269 				if (rc == MATRIXSSL_REQUEST_SEND || transferred < len) {
270 					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
271 				}
272 			}
273 		} else if (len < 0) {
274 			closeConn(cp, PS_ARG_FAIL);
275 			continue;	/* Next connection */
276 		}
277 
278 /*
279 		Check the file descriptor returned from select to see if the connection
280 		has data to be read
281  */
282 		if (FD_ISSET(cp->fd, &readfd)) {
283 READ_MORE:
284 			/* Get the ssl buffer and how much data it can accept */
285 			/* Note 0 is a return failure, unlike with matrixSslGetOutdata */
286 			if ((len = matrixSslGetReadbuf(cp->ssl, &buf)) <= 0) {
287 				closeConn(cp, PS_ARG_FAIL);
288 				continue;	/* Next connection */
289 			}
290 			if ((transferred = recv(cp->fd, buf, len, MSG_DONTWAIT)) < 0) {
291 				/* We could get EWOULDBLOCK despite the FD_ISSET on goto  */
292 #ifdef WIN32
293 				if (SOCKET_ERRNO != EWOULDBLOCK &&
294 					SOCKET_ERRNO != WSAEWOULDBLOCK) {
295 
296 #else
297 				if (SOCKET_ERRNO != EWOULDBLOCK) {
298 #endif
299 					closeConn(cp, PS_PLATFORM_FAIL);
300 				}
301 				continue;	/* Next connection */
302 			}
303 			/* If EOF, remote socket closed. This is semi-normal closure.
304 			   Officially, we should close on closure alert. */
305 			if (transferred == 0) {
306 /*				psTraceIntInfo("Closing connection %d on EOF\n", cp->fd); */
307 				closeConn(cp, 0);
308 				continue;	/* Next connection */
309 			}
310 /*
311 			Notify SSL state machine that we've received more data into the
312 			ssl buffer retreived with matrixSslGetReadbuf.
313  */
314 			if ((rc = matrixSslReceivedData(cp->ssl, (int32)transferred, &buf,
315 											(uint32*)&len)) < 0) {
316 				closeConn(cp, 0);
317 				continue;	/* Next connection */
318 			}
319 			/* Update activity time */
320 			psGetTime(&cp->time);
321 
322 PROCESS_MORE:
323 			/* Process any incoming plaintext application data */
324 			switch (rc) {
325 				case MATRIXSSL_HANDSHAKE_COMPLETE:
326 					/* If the protocol is server initiated, send data here */
327 					goto READ_MORE;
328 				case MATRIXSSL_APP_DATA:
329 					/* Remember, must handle if len == 0! */
330 					if ((rc = httpBasicParse(cp, buf, len)) < 0) {
331 						_psTrace("Couldn't parse HTTP data.  Closing conn.\n");
332 						closeConn(cp, PS_PROTOCOL_FAIL);
333 						continue; /* Next connection */
334 					}
335 					if (rc == HTTPS_COMPLETE) {
336 						if (httpWriteResponse(cp->ssl) < 0) {
337 							closeConn(cp, PS_PROTOCOL_FAIL);
338 							continue; /* Next connection */
339 						}
340 						/* For HTTP, we assume no pipelined requests, so we
341 						 close after parsing a single HTTP request */
342 						/* Ignore return of closure alert, it's optional */
343 						matrixSslEncodeClosureAlert(cp->ssl);
344 						rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len);
345 						if (rc > 0) {
346 							/* Additional data is available, but we ignore it */
347 							_psTrace("HTTP data parsing not supported, ignoring.\n");
348 							closeConn(cp, PS_SUCCESS);
349 							continue; /* Next connection */
350 						} else if (rc < 0) {
351 							closeConn(cp, PS_PROTOCOL_FAIL);
352 							continue; /* Next connection */
353 						}
354 						/* rc == 0, write out our response and closure alert */
355 						goto WRITE_MORE;
356 					}
357 					/* We processed a partial HTTP message */
358 					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
359 						goto READ_MORE;
360 					}
361 					goto PROCESS_MORE;
362 				case MATRIXSSL_REQUEST_SEND:
363 					/* Prevent us from reading again after the write,
364 					 although that wouldn't be the end of the world */
365 					FD_CLR(cp->fd, &readfd);
366 					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
367 					break;
368 				case MATRIXSSL_REQUEST_RECV:
369 					if (rSanity++ < GOTO_SANITY) goto READ_MORE;
370 					break;
371 				case MATRIXSSL_RECEIVED_ALERT:
372 					/* The first byte of the buffer is the level */
373 					/* The second byte is the description */
374 					if (*buf == SSL_ALERT_LEVEL_FATAL) {
375 						psTraceIntInfo("Fatal alert: %d, closing connection.\n",
376 									*(buf + 1));
377 						closeConn(cp, PS_PROTOCOL_FAIL);
378 						continue; /* Next connection */
379 					}
380 					/* Closure alert is normal (and best) way to close */
381 					if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
382 						closeConn(cp, PS_SUCCESS);
383 						continue; /* Next connection */
384 					}
385 					psTraceIntInfo("Warning alert: %d\n", *(buf + 1));
386 					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
387 						/* No more data in buffer. Might as well read for more. */
388 						goto READ_MORE;
389 					}
390 					goto PROCESS_MORE;
391 
392 				default:
393 					/* If rc <= 0 we fall here */
394 					closeConn(cp, PS_PROTOCOL_FAIL);
395 					continue; /* Next connection */
396 			}
397 			/* Always try to read more if we processed some data */
398 			if (rSanity++ < GOTO_SANITY) goto READ_MORE;
399 		} /*  readfd handling */
400 	}	/* connection loop */
401 	return PS_SUCCESS;
402 }
403 
404 /******************************************************************************/
405 /*
406 	Create an HTTP response and encode it to the SSL buffer
407  */
408 #define	TEST_SIZE	16000
409 static int32 httpWriteResponse(ssl_t *cp)
410 {
411 	unsigned char	*buf;
412 	int32			available;
413 
414 	if ((available = matrixSslGetWritebuf(cp, &buf,
415 							strlen((char *)g_httpResponseHdr) + 1)) < 0) {
416 		return PS_MEM_FAIL;
417 	}
418 	strncpy((char *)buf, (char *)g_httpResponseHdr, available);
419 	if (matrixSslEncodeWritebuf(cp, strlen((char *)buf)) < 0) {
420 		return PS_MEM_FAIL;
421 	}
422 	return MATRIXSSL_REQUEST_SEND;
423 }
424 
425 /******************************************************************************/
426 /*
427 	Main non-blocking SSL server
428 	Initialize MatrixSSL and sockets layer, and loop on select
429  */
430 int32 main(int32 argc, char **argv)
431 {
432 	sslKeys_t		*keys;
433 	SOCKET			lfd;
434 	int32			err, rc;
435 #ifdef WIN32
436 	WSADATA			wsaData;
437 	WSAStartup(MAKEWORD(1, 1), &wsaData);
438 #endif
439 
440 
441 	keys = NULL;
442 	DLListInit(&g_conns);
443 	g_exitFlag = 0;
444 	lfd = INVALID_SOCKET;
445 
446 #ifdef POSIX
447 	if (sighandlers() < 0) {
448 		return PS_PLATFORM_FAIL;
449 	}
450 #endif	/* POSIX */
451 	if ((rc = matrixSslOpen()) < 0) {
452 		_psTrace("MatrixSSL library init failure.  Exiting\n");
453 		return rc;
454 	}
455 	if (matrixSslNewKeys(&keys) < 0) {
456 		_psTrace("MatrixSSL library key init failure.  Exiting\n");
457 		return -1;
458 	}
459 
460 #ifdef USE_HEADER_KEYS
461 /*
462 	In-memory based keys
463 */
464 	if ((rc = matrixSslLoadRsaKeysMem(keys, certSrvBuf, sizeof(certSrvBuf),
465 				   privkeySrvBuf, sizeof(privkeySrvBuf), NULL, 0)) < 0) {
466 		_psTrace("No certificate material loaded.  Exiting\n");
467 		matrixSslDeleteKeys(keys);
468 		matrixSslClose();
469 		return rc;
470 	}
471 #else /* USE_HEADER_KEYS */
472 /*
473 	File based keys
474 */
475 	if ((rc = matrixSslLoadRsaKeys(keys, certSrvFile, privkeySrvFile, NULL,
476 			NULL)) < 0) {
477 		_psTrace("No certificate material loaded.  Exiting\n");
478 		matrixSslDeleteKeys(keys);
479 		matrixSslClose();
480 		return rc;
481 	}
482 #endif /* USE_HEADER_KEYS */
483 
484 
485 	/* Create the listening socket that will accept incoming connections */
486 	if ((lfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) {
487 		_psTraceInt("Can't listen on port %d\n", HTTPS_PORT);
488 		goto L_EXIT;
489 	}
490 
491 	/* Main select loop to handle sockets events */
492 	while (!g_exitFlag) {
493 		selectLoop(keys, lfd);
494 	}
495 
496 L_EXIT:
497 	if (lfd != INVALID_SOCKET) close(lfd);
498 	if (keys) matrixSslDeleteKeys(keys);
499 	matrixSslClose();
500 
501 	return 0;
502 }
503 
504 /******************************************************************************/
505 /*
506 	Close a socket and free associated SSL context and buffers
507  */
508 static void closeConn(httpConn_t *cp, int32 reason)
509 {
510 	unsigned char	*buf;
511 	int32			len;
512 
513 	DLListRemove(&cp->List);
514 	/* Quick attempt to send a closure alert, don't worry about failure */
515 	if (matrixSslEncodeClosureAlert(cp->ssl) >= 0) {
516 		if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) {
517 			if ((len = send(cp->fd, buf, len, MSG_DONTWAIT)) > 0) {
518 				matrixSslSentData(cp->ssl, len);
519 			}
520 		}
521 	}
522 	if (cp->parsebuf != NULL) {
523 		psAssert(cp->parsebuflen > 0);
524 		free(cp->parsebuf);
525 		cp->parsebuflen = 0;
526 	}
527 	matrixSslDeleteSession(cp->ssl);
528 	if (cp->fd != INVALID_SOCKET) {
529 		close(cp->fd);
530 	}
531 	if (reason >= 0) {
532 /*		_psTraceInt("=== Closing Client %d ===\n", cp->fd); */
533 	} else {
534 		_psTraceInt("=== Closing Client %d on Error ===\n", cp->fd);
535 	}
536 	free(cp);
537 }
538 
539 /******************************************************************************/
540 /*
541 	Establish a listening socket for incomming connections
542  */
543 static SOCKET socketListen(short port, int32 *err)
544 {
545 	struct sockaddr_in	addr;
546 	SOCKET				fd;
547 
548 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
549 		_psTrace("Error creating listen socket\n");
550 		*err = SOCKET_ERRNO;
551 		return INVALID_SOCKET;
552 	}
553 
554 	setSocketOptions(fd);
555 
556 	addr.sin_family = AF_INET;
557 	addr.sin_port = htons(port);
558 	addr.sin_addr.s_addr = INADDR_ANY;
559 	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
560 		_psTrace("Can't bind socket. Port in use or insufficient privilege\n");
561 		*err = SOCKET_ERRNO;
562 		return INVALID_SOCKET;
563 	}
564 	if (listen(fd, SOMAXCONN) < 0) {
565 		_psTrace("Error listening on socket\n");
566 		*err = SOCKET_ERRNO;
567 		return INVALID_SOCKET;
568 	}
569 	_psTraceInt("Listening on port %d\n", port);
570 	return fd;
571 }
572 
573 /******************************************************************************/
574 /*
575 	Make sure the socket is not inherited by exec'd processes
576 	Set the REUSE flag to minimize the number of sockets in TIME_WAIT
577 	Then we set REUSEADDR, NODELAY and NONBLOCK on the socket
578 */
579 static void setSocketOptions(SOCKET fd)
580 {
581 	int32 rc;
582 
583 #ifdef POSIX
584 	fcntl(fd, F_SETFD, FD_CLOEXEC);
585 #endif
586 	rc = 1;
587 	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));
588 #ifdef POSIX
589 	rc = 1;
590 	setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&rc, sizeof(rc));
591 	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
592 #elif defined(WIN32)
593 	rc = 1;		/* 1 for non-block, 0 for block */
594     ioctlsocket(fd, FIONBIO, &rc);
595 #endif
596 #ifdef __APPLE__  /* MAC OS X */
597     rc = 1;
598     setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&rc, sizeof(rc));
599 #endif
600 }
601 
602 #ifdef POSIX
603 /******************************************************************************/
604 /*
605 	Handle some signals on POSIX platforms
606 	Lets ctrl-c do a clean exit of the server.
607  */
608 static int32 sighandlers(void)
609 {
610 	if (signal(SIGINT, sigintterm_handler) == SIG_ERR ||
611 			signal(SIGTERM, sigintterm_handler) == SIG_ERR ||
612 			signal(SIGPIPE, SIG_IGN) == SIG_ERR ||
613 			signal(SIGSEGV, sigsegv_handler) == SIG_ERR) {
614 		return PS_PLATFORM_FAIL;
615 	}
616 	return 0;
617 }
618 
619 /* Warn on segmentation violation */
620 static void sigsegv_handler(int unused)
621 {
622 	printf("Segfault! Please report this as a bug to support@peersec.com\n");
623 	exit(EXIT_FAILURE);
624 }
625 
626 /* catch ctrl-c or sigterm */
627 static void sigintterm_handler(int unused)
628 {
629 	g_exitFlag = 1; /* Rudimentary exit flagging */
630 	printf("Exiting due to interrupt.\n");
631 }
632 #endif /* POSIX */
633 
634 
635 #else
636 
637 /******************************************************************************/
638 /*
639     Stub main for compiling without server enabled
640 */
641 int32 main(int32 argc, char **argv)
642 {
643     printf("USE_SERVER_SIDE_SSL must be enabled in matrixsslConfig.h at build" \
644             " time to run this application\n");
645     return -1;
646 }
647 #endif /* USE_SERVER_SIDE_SSL */
648 
649 /******************************************************************************/
650 
651