summaryrefslogtreecommitdiff
path: root/release/src/router/matrixssl/examples/sslSocket.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 13:58:15 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 13:58:15 +0100
commit4aca87515a5083ae0e31ce3177189fd43b6d05ac (patch)
tree7b1d9a31393ca090757dc6f0d3859b4fcd93f271 /release/src/router/matrixssl/examples/sslSocket.c
parent008d0be72b2f160382c6e880765e96b64a050c65 (diff)
downloadtomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.gz
tomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.bz2
patch to Vanilla Tomato 1.28
Diffstat (limited to 'release/src/router/matrixssl/examples/sslSocket.c')
-rw-r--r--release/src/router/matrixssl/examples/sslSocket.c1025
1 files changed, 1025 insertions, 0 deletions
diff --git a/release/src/router/matrixssl/examples/sslSocket.c b/release/src/router/matrixssl/examples/sslSocket.c
new file mode 100644
index 00000000..39c51871
--- /dev/null
+++ b/release/src/router/matrixssl/examples/sslSocket.c
@@ -0,0 +1,1025 @@
+/*
+ * socketLayer.c
+ * Release $Name: MATRIXSSL_1_8_8_OPEN $
+ *
+ * Sample SSL socket layer for MatrixSSL example exectuables
+ */
+/*
+ * Copyright (c) PeerSec Networks, 2002-2009. All Rights Reserved.
+ * The latest version of this code is available at http://www.matrixssl.org
+ *
+ * This software is open source; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This General Public License does NOT permit incorporating this software
+ * into proprietary programs. If you are unable to comply with the GPL, a
+ * commercial license for this software may be purchased from PeerSec Networks
+ * at http://www.peersec.com
+ *
+ * This program is distributed in WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/******************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "sslSocket.h"
+
+/******************************************************************************/
+/*
+ An EXAMPLE socket layer API for the MatrixSSL library.
+*/
+
+/******************************************************************************/
+/*
+ Server side. Set up a listen socket. This code is not specific to SSL.
+*/
+SOCKET socketListen(short port, int *err)
+{
+ struct sockaddr_in addr;
+ SOCKET fd;
+ int rc;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ fprintf(stderr, "Error creating listen socket\n");
+ *err = getSocketError();
+ return INVALID_SOCKET;
+ }
+/*
+ Make sure the socket is not inherited by exec'd processes
+ Set the REUSE flag to minimize the number of sockets in TIME_WAIT
+*/
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ rc = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));
+
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ fprintf(stderr,
+ "Can't bind socket. Port in use or insufficient privilege\n");
+ *err = getSocketError();
+ return INVALID_SOCKET;
+ }
+ if (listen(fd, SOMAXCONN) < 0) {
+ fprintf(stderr, "Error listening on socket\n");
+ *err = getSocketError();
+ return INVALID_SOCKET;
+ }
+ return fd;
+}
+
+/******************************************************************************/
+/*
+ Server side. Accept a new socket connection off our listen socket.
+ This code is not specific to SSL.
+*/
+SOCKET socketAccept(SOCKET listenfd, int *err)
+{
+ struct sockaddr_in addr;
+ SOCKET fd;
+ int len;
+/*
+ Wait(blocking)/poll(non-blocking) for an incoming connection
+*/
+ len = sizeof(addr);
+ if ((fd = accept(listenfd, (struct sockaddr *)&addr, &len))
+ == INVALID_SOCKET) {
+ *err = getSocketError();
+ if (*err != WOULD_BLOCK) {
+ fprintf(stderr, "Error %d accepting new socket\n", *err);
+ }
+ return INVALID_SOCKET;
+ }
+/*
+ fd is the newly accepted socket. Disable Nagle on this socket.
+ Set blocking mode as default
+*/
+/* fprintf(stdout, "Connection received from %d.%d.%d.%d\n",
+ addr.sin_addr.S_un.S_un_b.s_b1,
+ addr.sin_addr.S_un.S_un_b.s_b2,
+ addr.sin_addr.S_un.S_un_b.s_b3,
+ addr.sin_addr.S_un.S_un_b.s_b4);
+*/
+ setSocketNodelay(fd);
+ setSocketBlock(fd);
+ return fd;
+}
+
+/******************************************************************************/
+/*
+ Client side. Open a socket connection to a remote ip and port.
+ This code is not specific to SSL.
+*/
+SOCKET socketConnect(char *ip, short port, int *err)
+{
+ struct sockaddr_in addr;
+ SOCKET fd;
+ int rc;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ fprintf(stderr, "Error creating socket\n");
+ *err = getSocketError();
+ return INVALID_SOCKET;
+ }
+/*
+ Make sure the socket is not inherited by exec'd processes
+ Set the REUSEADDR flag to minimize the number of sockets in TIME_WAIT
+*/
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ rc = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));
+ setSocketNodelay(fd);
+/*
+ Turn on blocking mode for the connecting socket
+*/
+ setSocketBlock(fd);
+
+ memset((char *) &addr, 0x0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = inet_addr(ip);
+ rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+#if WIN
+ if (rc != 0) {
+#else
+ if (rc < 0) {
+#endif
+ *err = getSocketError();
+ return INVALID_SOCKET;
+ }
+ return fd;
+}
+
+/******************************************************************************/
+/*
+ Server side. Accept an incomming SSL connection request.
+ 'conn' will be filled in with information about the accepted ssl connection
+
+ return -1 on error, 0 on success, or WOULD_BLOCK for non-blocking sockets
+*/
+int sslAccept(sslConn_t **cpp, SOCKET fd, sslKeys_t *keys,
+ int (*certValidator)(sslCertInfo_t *t, void *arg), int flags)
+{
+ sslConn_t *conn;
+ unsigned char buf[1024];
+ int status, rc;
+/*
+ Associate a new ssl session with this socket. The session represents
+ the state of the ssl protocol over this socket. Session caching is
+ handled automatically by this api.
+*/
+ conn = calloc(sizeof(sslConn_t), 1);
+ conn->fd = fd;
+ if (matrixSslNewSession(&conn->ssl, keys, NULL,
+ SSL_FLAGS_SERVER | flags) < 0) {
+ sslFreeConnection(&conn);
+ return -1;
+ }
+/*
+ MatrixSSL doesn't provide buffers for data internally. Define them
+ here to support buffered reading and writing for non-blocking sockets.
+ Although it causes quite a bit more work, we support dynamically growing
+ the buffers as needed. Alternately, we could define 16K buffers here
+ and not worry about growing them.
+*/
+ memset(&conn->inbuf, 0x0, sizeof(sslBuf_t));
+ conn->insock.size = 1024;
+ conn->insock.start = conn->insock.end = conn->insock.buf =
+ (unsigned char *)malloc(conn->insock.size);
+ conn->outsock.size = 1024;
+ conn->outsock.start = conn->outsock.end = conn->outsock.buf =
+ (unsigned char *)malloc(conn->outsock.size);
+ conn->inbuf.size = 0;
+ conn->inbuf.start = conn->inbuf.end = conn->inbuf.buf = NULL;
+ *cpp = conn;
+
+readMore:
+ rc = sslRead(conn, buf, sizeof(buf), &status);
+/*
+ Reading handshake records should always return 0 bytes, we aren't
+ expecting any data yet.
+*/
+ if (rc == 0) {
+ if (status == SSLSOCKET_EOF || status == SSLSOCKET_CLOSE_NOTIFY) {
+ sslFreeConnection(&conn);
+ return -1;
+ }
+ if (matrixSslHandshakeIsComplete(conn->ssl) == 0) {
+ goto readMore;
+ }
+ } else if (rc > 0) {
+ socketAssert(0);
+ return -1;
+ } else {
+ fprintf(stderr, "sslRead error in sslAccept\n");
+ sslFreeConnection(&conn);
+ return -1;
+ }
+ *cpp = conn;
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Client side. Make a socket connection and go through the SSL handshake
+ phase in blocking mode. The last parameter is an optional function
+ callback for user-level certificate validation. NULL if not needed.
+*/
+int sslConnect(sslConn_t **cpp, SOCKET fd, sslKeys_t *keys,
+ sslSessionId_t *id, short cipherSuite,
+ int (*certValidator)(sslCertInfo_t *t, void *arg))
+{
+ sslConn_t *conn;
+
+/*
+ Create a new SSL session for the new socket and register the
+ user certificate validator
+*/
+ conn = calloc(sizeof(sslConn_t), 1);
+ conn->fd = fd;
+ if (matrixSslNewSession(&conn->ssl, keys, id, 0) < 0) {
+ sslFreeConnection(&conn);
+ return -1;
+ }
+ matrixSslSetCertValidator(conn->ssl, certValidator, keys);
+
+ *cpp = sslDoHandshake(conn, cipherSuite);
+
+ if (*cpp == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Construct the initial HELLO message to send to the server and initiate
+ the SSL handshake. Can be used in the re-handshake scenario as well.
+*/
+sslConn_t *sslDoHandshake(sslConn_t *conn, short cipherSuite)
+{
+ char buf[1024];
+ int bytes, status, rc;
+
+/*
+ MatrixSSL doesn't provide buffers for data internally. Define them
+ here to support buffered reading and writing for non-blocking sockets.
+ Although it causes quite a bit more work, we support dynamically growing
+ the buffers as needed. Alternately, we could define 16K buffers here
+ and not worry about growing them.
+*/
+ conn->insock.size = 1024;
+ conn->insock.start = conn->insock.end = conn->insock.buf =
+ (unsigned char *)malloc(conn->insock.size);
+ conn->outsock.size = 1024;
+ conn->outsock.start = conn->outsock.end = conn->outsock.buf =
+ (unsigned char *)malloc(conn->outsock.size);
+ conn->inbuf.size = 0;
+ conn->inbuf.start = conn->inbuf.end = conn->inbuf.buf = NULL;
+
+ bytes = matrixSslEncodeClientHello(conn->ssl, &conn->outsock, cipherSuite);
+ if (bytes < 0) {
+ socketAssert(bytes < 0);
+ goto error;
+ }
+/*
+ Send the hello with a blocking write
+*/
+ if (psSocketWrite(conn->fd, &conn->outsock) < 0) {
+ fprintf(stdout, "Error in socketWrite\n");
+ goto error;
+ }
+ conn->outsock.start = conn->outsock.end = conn->outsock.buf;
+/*
+ Call sslRead to work through the handshake. Not actually expecting
+ data back, so the finished case is simply when the handshake is
+ complete.
+*/
+readMore:
+ rc = sslRead(conn, buf, sizeof(buf), &status);
+/*
+ Reading handshake records should always return 0 bytes, we aren't
+ expecting any data yet.
+*/
+ if (rc == 0) {
+ if (status == SSLSOCKET_EOF || status == SSLSOCKET_CLOSE_NOTIFY) {
+ goto error;
+ }
+ if (matrixSslHandshakeIsComplete(conn->ssl) == 0) {
+ goto readMore;
+ }
+ } else if (rc > 0) {
+ fprintf(stderr, "sslRead got %d data in sslDoHandshake %s\n", rc, buf);
+ goto readMore;
+ } else {
+ fprintf(stderr, "sslRead error in sslDoHandhake\n");
+ goto error;
+ }
+
+ return conn;
+
+error:
+ sslFreeConnection(&conn);
+ return NULL;
+}
+
+/******************************************************************************/
+/*
+ An example socket sslRead implementation that handles the ssl handshake
+ transparently. Caller passes in allocated buf and length.
+
+ Return codes are as follows:
+
+ -1 return code is an error. If a socket level error, error code is
+ contained in status parameter. If using a non-blocking socket
+ implementation the caller should check for non-fatal errors such as
+ WOULD_BLOCK before closing the connection. A zero value
+ in status indicates an error with this routine.
+
+ A positive integer return code is the number of bytes successfully read
+ into the supplied buffer. User can call sslRead again on the updated
+ buffer is there is more to be read.
+
+ 0 return code indicates the read was successful, but there was no data
+ to be returned. If status is set to zero, this is a case internal
+ to the sslAccept and sslConnect functions that a handshake
+ message has been exchanged. If status is set to SOCKET_EOF
+ the connection has been closed by the other side.
+
+*/
+int sslRead(sslConn_t *cp, char *buf, int len, int *status)
+{
+ int bytes, rc, remaining;
+ unsigned char error, alertLevel, alertDescription, performRead;
+
+ *status = 0;
+
+ if (cp->ssl == NULL || len <= 0) {
+ return -1;
+ }
+/*
+ If inbuf is valid, then we have previously decoded data that must be
+ returned, return as much as possible. Once all buffered data is
+ returned, free the inbuf.
+*/
+ if (cp->inbuf.buf) {
+ if (cp->inbuf.start < cp->inbuf.end) {
+ remaining = (int)(cp->inbuf.end - cp->inbuf.start);
+ bytes = (int)min(len, remaining);
+ memcpy(buf, cp->inbuf.start, bytes);
+ cp->inbuf.start += bytes;
+ return bytes;
+ }
+ free(cp->inbuf.buf);
+ cp->inbuf.buf = NULL;
+ }
+/*
+ Pack the buffered socket data (if any) so that start is at zero.
+*/
+ if (cp->insock.buf < cp->insock.start) {
+ if (cp->insock.start == cp->insock.end) {
+ cp->insock.start = cp->insock.end = cp->insock.buf;
+ } else {
+ memmove(cp->insock.buf, cp->insock.start, cp->insock.end - cp->insock.start);
+ cp->insock.end -= (cp->insock.start - cp->insock.buf);
+ cp->insock.start = cp->insock.buf;
+ }
+ }
+/*
+ Read up to as many bytes as there are remaining in the buffer. We could
+ Have encrypted data already cached in conn->insock, but might as well read more
+ if we can.
+*/
+ performRead = 0;
+readMore:
+ if (cp->insock.end == cp->insock.start || performRead) {
+ performRead = 1;
+ bytes = recv(cp->fd, (char *)cp->insock.end,
+ (int)((cp->insock.buf + cp->insock.size) - cp->insock.end), MSG_NOSIGNAL);
+ if (bytes == SOCKET_ERROR) {
+ *status = getSocketError();
+ return -1;
+ }
+ if (bytes == 0) {
+ *status = SSLSOCKET_EOF;
+ return 0;
+ }
+ cp->insock.end += bytes;
+ }
+/*
+ Define a temporary sslBuf
+*/
+ cp->inbuf.start = cp->inbuf.end = cp->inbuf.buf = malloc(len);
+ cp->inbuf.size = len;
+/*
+ Decode the data we just read from the socket
+*/
+decodeMore:
+ error = 0;
+ alertLevel = 0;
+ alertDescription = 0;
+
+ rc = matrixSslDecode(cp->ssl, &cp->insock, &cp->inbuf, &error, &alertLevel,
+ &alertDescription);
+ switch (rc) {
+/*
+ Successfully decoded a record that did not return data or require a response.
+*/
+ case SSL_SUCCESS:
+ return 0;
+/*
+ Successfully decoded an application data record, and placed in tmp buf
+*/
+ case SSL_PROCESS_DATA:
+/*
+ Copy as much as we can from the temp buffer into the caller's buffer
+ and leave the remainder in conn->inbuf until the next call to read
+ It is possible that len > data in buffer if the encoded record
+ was longer than len, but the decoded record isn't!
+*/
+ rc = (int)(cp->inbuf.end - cp->inbuf.start);
+ rc = min(rc, len);
+ memcpy(buf, cp->inbuf.start, rc);
+ cp->inbuf.start += rc;
+ return rc;
+/*
+ We've decoded a record that requires a response into tmp
+ If there is no data to be flushed in the out buffer, we can write out
+ the contents of the tmp buffer. Otherwise, we need to append the data
+ to the outgoing data buffer and flush it out.
+*/
+ case SSL_SEND_RESPONSE:
+ bytes = send(cp->fd, (char *)cp->inbuf.start,
+ (int)(cp->inbuf.end - cp->inbuf.start), MSG_NOSIGNAL);
+ if (bytes == SOCKET_ERROR) {
+ *status = getSocketError();
+ if (*status != WOULD_BLOCK) {
+ fprintf(stdout, "Socket send error: %d\n", *status);
+ goto readError;
+ }
+ *status = 0;
+ }
+ cp->inbuf.start += bytes;
+ if (cp->inbuf.start < cp->inbuf.end) {
+/*
+ This must be a non-blocking socket since it didn't all get sent
+ out and there was no error. We want to finish the send here
+ simply because we are likely in the SSL handshake.
+*/
+ setSocketBlock(cp->fd);
+ bytes = send(cp->fd, (char *)cp->inbuf.start,
+ (int)(cp->inbuf.end - cp->inbuf.start), MSG_NOSIGNAL);
+ if (bytes == SOCKET_ERROR) {
+ *status = getSocketError();
+ goto readError;
+ }
+ cp->inbuf.start += bytes;
+ socketAssert(cp->inbuf.start == cp->inbuf.end);
+/*
+ Can safely set back to non-blocking because we wouldn't
+ have got here if this socket wasn't non-blocking to begin with.
+*/
+ setSocketNonblock(cp->fd);
+ }
+ cp->inbuf.start = cp->inbuf.end = cp->inbuf.buf;
+ return 0;
+/*
+ There was an error decoding the data, or encoding the out buffer.
+ There may be a response data in the out buffer, so try to send.
+ We try a single hail-mary send of the data, and then close the socket.
+ Since we're closing on error, we don't worry too much about a clean flush.
+*/
+ case SSL_ERROR:
+ fprintf(stderr, "SSL: Closing on protocol error %d\n", error);
+ if (cp->inbuf.start < cp->inbuf.end) {
+ setSocketNonblock(cp->fd);
+ bytes = send(cp->fd, (char *)cp->inbuf.start,
+ (int)(cp->inbuf.end - cp->inbuf.start), MSG_NOSIGNAL);
+ }
+ goto readError;
+/*
+ We've decoded an alert. The level and description passed into
+ matrixSslDecode are filled in with the specifics.
+*/
+ case SSL_ALERT:
+ if (alertDescription == SSL_ALERT_CLOSE_NOTIFY) {
+ *status = SSLSOCKET_CLOSE_NOTIFY;
+ goto readZero;
+ }
+ fprintf(stderr, "SSL: Closing on client alert %d: %d\n",
+ alertLevel, alertDescription);
+ goto readError;
+/*
+ We have a partial record, we need to read more data off the socket.
+ If we have a completely full conn->insock buffer, we'll need to grow it
+ here so that we CAN read more data when called the next time.
+*/
+ case SSL_PARTIAL:
+ if (cp->insock.start == cp->insock.buf && cp->insock.end ==
+ (cp->insock.buf + cp->insock.size)) {
+ if (cp->insock.size > SSL_MAX_BUF_SIZE) {
+ goto readError;
+ }
+ cp->insock.size *= 2;
+ cp->insock.start = cp->insock.buf =
+ (unsigned char *)realloc(cp->insock.buf, cp->insock.size);
+ cp->insock.end = cp->insock.buf + (cp->insock.size / 2);
+ }
+ if (!performRead) {
+ performRead = 1;
+ free(cp->inbuf.buf);
+ cp->inbuf.buf = NULL;
+ goto readMore;
+ } else {
+ goto readZero;
+ }
+/*
+ The out buffer is too small to fit the decoded or response
+ data. Increase the size of the buffer and call decode again
+*/
+ case SSL_FULL:
+ cp->inbuf.size *= 2;
+ if (cp->inbuf.buf != (unsigned char*)buf) {
+ free(cp->inbuf.buf);
+ cp->inbuf.buf = NULL;
+ }
+ cp->inbuf.start = cp->inbuf.end = cp->inbuf.buf =
+ (unsigned char *)malloc(cp->inbuf.size);
+ goto decodeMore;
+ }
+/*
+ We consolidated some of the returns here because we must ensure
+ that conn->inbuf is cleared if pointing at caller's buffer, otherwise
+ it will be freed later on.
+*/
+readZero:
+ if (cp->inbuf.buf == (unsigned char*)buf) {
+ cp->inbuf.buf = NULL;
+ }
+ return 0;
+readError:
+ if (cp->inbuf.buf == (unsigned char*)buf) {
+ cp->inbuf.buf = NULL;
+ }
+ return -1;
+}
+
+/******************************************************************************/
+/*
+ Example sslWrite functionality. Takes care of encoding the input buffer
+ and sending it out on the connection.
+
+ Return codes are as follows:
+
+ -1 return code is an error. If a socket level error, error code is
+ contained in status. If using a non-blocking socket
+ implementation the caller should check for non-fatal errors such as
+ WOULD_BLOCK before closing the connection. A zero value
+ in status indicates an error with this routine.
+
+ A positive integer return value indicates the number of bytes succesfully
+ written on the connection. Should always match the len parameter.
+
+ 0 return code indicates the write must be called again with the same
+ parameters.
+*/
+int sslWrite(sslConn_t *cp, char *buf, int len, int *status)
+{
+ int rc;
+
+ *status = 0;
+/*
+ Pack the buffered socket data (if any) so that start is at zero.
+*/
+ if (cp->outsock.buf < cp->outsock.start) {
+ if (cp->outsock.start == cp->outsock.end) {
+ cp->outsock.start = cp->outsock.end = cp->outsock.buf;
+ } else {
+ memmove(cp->outsock.buf, cp->outsock.start, cp->outsock.end - cp->outsock.start);
+ cp->outsock.end -= (cp->outsock.start - cp->outsock.buf);
+ cp->outsock.start = cp->outsock.buf;
+ }
+ }
+/*
+ If there is buffered output data, the caller must be trying to
+ send the same amount of data as last time. We don't support
+ sending additional data until the original buffered request has
+ been completely sent.
+*/
+ if (cp->outBufferCount > 0 && len != cp->outBufferCount) {
+ socketAssert(len != cp->outBufferCount);
+ return -1;
+ }
+/*
+ If we don't have buffered data, encode the caller's data
+*/
+ if (cp->outBufferCount == 0) {
+retryEncode:
+ rc = matrixSslEncode(cp->ssl, (unsigned char *)buf, len, &cp->outsock);
+ switch (rc) {
+ case SSL_ERROR:
+ return -1;
+ case SSL_FULL:
+ if (cp->outsock.size > SSL_MAX_BUF_SIZE) {
+ return -1;
+ }
+ cp->outsock.size *= 2;
+ cp->outsock.buf =
+ (unsigned char *)realloc(cp->outsock.buf, cp->outsock.size);
+ cp->outsock.end = cp->outsock.buf + (cp->outsock.end - cp->outsock.start);
+ cp->outsock.start = cp->outsock.buf;
+ goto retryEncode;
+ }
+ }
+/*
+ We've got data to send.
+*/
+ rc = send(cp->fd, (char *)cp->outsock.start,
+ (int)(cp->outsock.end - cp->outsock.start), MSG_NOSIGNAL);
+ if (rc == SOCKET_ERROR) {
+ *status = getSocketError();
+ return -1;
+ }
+ cp->outsock.start += rc;
+/*
+ If we wrote it all return the length, otherwise remember the number of
+ bytes passed in, and return 0 to be called again later.
+*/
+ if (cp->outsock.start == cp->outsock.end) {
+ cp->outBufferCount = 0;
+ return len;
+ }
+ cp->outBufferCount = len;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Send a close alert
+*/
+void sslWriteClosureAlert(sslConn_t *cp)
+{
+ if (cp != NULL) {
+ cp->outsock.start = cp->outsock.end = cp->outsock.buf;
+ matrixSslEncodeClosureAlert(cp->ssl, &cp->outsock);
+ setSocketNonblock(cp->fd);
+ send(cp->fd, cp->outsock.start,
+ (int)(cp->outsock.end - cp->outsock.start), MSG_NOSIGNAL);
+ }
+}
+
+/******************************************************************************/
+/*
+ Server initiated rehandshake. Builds and sends the HELLO_REQUEST message
+*/
+void sslRehandshake(sslConn_t *cp)
+{
+ matrixSslEncodeHelloRequest(cp->ssl, &cp->outsock);
+ psSocketWrite(cp->fd, &cp->outsock);
+ cp->outsock.start = cp->outsock.end = cp->outsock.buf;
+}
+
+/******************************************************************************/
+/*
+ Close a seesion that was opened with sslAccept or sslConnect and
+ free the insock and outsock buffers
+*/
+void sslFreeConnection(sslConn_t **cpp)
+{
+ sslConn_t *conn;
+
+ conn = *cpp;
+ matrixSslDeleteSession(conn->ssl);
+ conn->ssl = NULL;
+ if (conn->insock.buf) {
+ free(conn->insock.buf);
+ conn->insock.buf = NULL;
+ }
+ if (conn->outsock.buf) {
+ free(conn->outsock.buf);
+ conn->outsock.buf = NULL;
+ }
+ if (conn->inbuf.buf) {
+ free(conn->inbuf.buf);
+ conn->inbuf.buf = NULL;
+ }
+ free(conn);
+ *cpp = NULL;
+}
+
+/******************************************************************************/
+/*
+ free the insock and outsock buffers
+*/
+void sslFreeConnectionBuffers(sslConn_t **cpp)
+{
+ sslConn_t *conn;
+
+ conn = *cpp;
+ if (conn->insock.buf) {
+ free(conn->insock.buf);
+ conn->insock.buf = NULL;
+ }
+ if (conn->outsock.buf) {
+ free(conn->outsock.buf);
+ conn->outsock.buf = NULL;
+ }
+ if (conn->inbuf.buf) {
+ free(conn->inbuf.buf);
+ conn->inbuf.buf = NULL;
+ }
+}
+
+/******************************************************************************/
+/*
+ Set the socket to non blocking mode and perform a few extra tricks
+ to make sure the socket closes down cross platform
+*/
+void socketShutdown(SOCKET sock)
+{
+ char buf[32];
+
+ if (sock != INVALID_SOCKET) {
+ setSocketNonblock(sock);
+ if (shutdown(sock, 1) >= 0) {
+ while (recv(sock, buf, sizeof(buf), 0) > 0);
+ }
+ closesocket(sock);
+ }
+}
+
+/******************************************************************************/
+/*
+ Perform a blocking write of data to a socket
+*/
+int psSocketWrite(SOCKET sock, sslBuf_t *out)
+{
+ unsigned char *s;
+ int bytes;
+
+ s = out->start;
+ while (out->start < out->end) {
+ bytes = send(sock, out->start, (int)(out->end - out->start), MSG_NOSIGNAL);
+ if (bytes == SOCKET_ERROR) {
+ return -1;
+ }
+ out->start += bytes;
+ }
+ return (int)(out->start - s);
+}
+
+int psSocketRead(SOCKET sock, sslBuf_t **out, int *status)
+{
+ sslBuf_t *local;
+ char *c;
+ int bytes;
+
+ local = *out;
+ c = local->start;
+
+ bytes = recv(sock, c, (int)((local->buf + local->size) - local->end), MSG_NOSIGNAL);
+ if (bytes == SOCKET_ERROR) {
+ *status = getSocketError();
+ return -1;
+ }
+ if (bytes == 0) {
+ *status = SSLSOCKET_EOF;
+ return 0;
+ }
+ local->end += bytes;
+ return bytes;
+}
+
+/******************************************************************************/
+/*
+ Turn on socket blocking mode (and set CLOEXEC on LINUX for kicks).
+*/
+void setSocketBlock(SOCKET sock)
+{
+#if _WIN32
+ int block = 0;
+ ioctlsocket(sock, FIONBIO, &block);
+#elif LINUX
+ fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) & ~O_NONBLOCK);
+ fcntl(sock, F_SETFD, FD_CLOEXEC);
+#endif
+}
+
+/******************************************************************************/
+/*
+ Turn off socket blocking mode.
+*/
+void setSocketNonblock(SOCKET sock)
+{
+#if _WIN32
+ int block = 1;
+ ioctlsocket(sock, FIONBIO, &block);
+#elif LINUX
+ fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
+#endif
+}
+
+/******************************************************************************/
+/*
+ Disable the Nagle algorithm for less latency in RPC
+ http://www.faqs.org/rfcs/rfc896.html
+ http://www.w3.org/Protocols/HTTP/Performance/Nagle/
+*/
+void setSocketNodelay(SOCKET sock)
+{
+#if _WIN32
+ BOOL tmp = TRUE;
+#else
+ int tmp = 1;
+#endif /* WIN32 */
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&tmp, sizeof(tmp));
+}
+
+/******************************************************************************/
+/*
+ Set a breakpoint in this function to catch asserts.
+ This function is called whenever an assert is triggered. Useful because
+ VisualStudio often won't show the right line of code if DebugBreak() is
+ called directly, and abort() may not be desireable on LINUX.
+*/
+void breakpoint()
+{
+ static int preventInline = 0;
+#if _WIN32
+ DebugBreak();
+#elif LINUX
+ abort();
+#endif
+}
+
+
+/******************************************************************************/
+/*
+ Parse an ASCII command line string. Assumes a NULL terminated space
+ separated list of command line arguments. Uses this info to create an argv
+ array.
+
+ Notes:
+ handles double quotes
+ args gets hacked up! can't pass in static string!
+ not thread safe, so should be called b4 any thread creation
+ we currently hardcode argv[0] cause none of our apps need it
+ */
+
+#if WINCE || VXWORKS
+
+void parseCmdLineArgs(char *args, int *pargc, char ***pargv)
+{
+ char **argv;
+ char *ptr;
+ int size, i;
+
+/*
+ * Figure out the number of elements in our argv array.
+ * We know we need an argv array of at least 3, since we have the
+ * program name, an argument, and a NULL in the array.
+ */
+ for (size = 3, ptr = args; ptr && *ptr != '\0'; ptr++) {
+ if (isspace(*ptr)) {
+ size++;
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+ if (*ptr == '\0') {
+ break;
+ }
+ }
+ }
+/*
+ * This is called from main, so don't use psMalloc here or
+ * all the stats will be wrong.
+ */
+ argv = (char**) malloc(size * sizeof(char*));
+ *pargv = argv;
+
+ for (i = 1, ptr = args; ptr && *ptr != '\0'; i++) {
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+ if (*ptr == '\0') {
+ break;
+ }
+/*
+ * Handle double quoted arguments. Treat everything within
+ * the double quote as one arg.
+ */
+ if (*ptr == '"') {
+ ptr++;
+ argv[i] = ptr;
+ while ((*ptr != '\0') && (*ptr != '"')) {
+ ptr++;
+ }
+ } else {
+ argv[i] = ptr;
+ while (*ptr != '\0' && !isspace(*ptr)) {
+ ptr++;
+ }
+ }
+ if (*ptr != '\0') {
+ *ptr = '\0';
+ ptr++;
+ }
+ }
+ argv[i] = NULL;
+ *pargc = i ;
+
+ argv[0] = "PeerSec";
+ for (ptr = argv[0]; *ptr; ptr++) {
+ if (*ptr == '\\') {
+ *ptr = '/';
+ }
+ }
+}
+#endif /* WINCE || VXWORKS */
+
+#ifdef WINCE
+
+/******************************************************************************/
+/*
+ The following functions implement a unixlike time() function for WINCE.
+
+ NOTE: this code is copied from the os layer in win.c to expose it for use
+ in example applications.
+ */
+
+static FILETIME YearToFileTime(WORD wYear)
+{
+ SYSTEMTIME sbase;
+ FILETIME fbase;
+
+ sbase.wYear = wYear;
+ sbase.wMonth = 1;
+ sbase.wDayOfWeek = 1; //assumed
+ sbase.wDay = 1;
+ sbase.wHour = 0;
+ sbase.wMinute = 0;
+ sbase.wSecond = 0;
+ sbase.wMilliseconds = 0;
+
+ SystemTimeToFileTime( &sbase, &fbase );
+
+ return fbase;
+}
+
+time_t time() {
+
+ __int64 time1, time2, iTimeDiff;
+ FILETIME fileTime1, fileTime2;
+ SYSTEMTIME sysTime;
+
+/*
+ Get 1970's filetime.
+*/
+ fileTime1 = YearToFileTime(1970);
+
+/*
+ Get the current filetime time.
+*/
+ GetSystemTime(&sysTime);
+ SystemTimeToFileTime(&sysTime, &fileTime2);
+
+
+/*
+ Stuff the 2 FILETIMEs into their own __int64s.
+*/
+ time1 = fileTime1.dwHighDateTime;
+ time1 <<= 32;
+ time1 |= fileTime1.dwLowDateTime;
+
+ time2 = fileTime2.dwHighDateTime;
+ time2 <<= 32;
+ time2 |= fileTime2.dwLowDateTime;
+
+/*
+ Get the difference of the two64-bit ints.
+
+ This is he number of 100-nanosecond intervals since Jan. 1970. So
+ we divide by 10000 to get seconds.
+ */
+ iTimeDiff = (time2 - time1) / 10000000;
+ return (int)iTimeDiff;
+}
+#endif /* WINCE */
+
+/******************************************************************************/
+
+
+
+
+