📄 sslsocket.c
字号:
case SSL_ALERT:
if (alertDescription == SSL_ALERT_CLOSE_NOTIFY) {
*status = SSLSOCKET_CLOSE_NOTIFY;
goto readZero;
}
syslog( LOG_WARNING, "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( preventInline ) {
}
#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 */
/******************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -