ssize_t SSL_RecvDataAndFd(SSLSock sslSock, // IN/OUT char *buf, // OUT size_t num, // IN int *fd) // OUT { int ret; ASSERT(sslSock); ASSERT(fd); *fd = -1; /* * No fd passing over socket or Windows. Windows needs different code. */ #ifdef _WIN32 return SSL_Read(sslSock, buf, num); #else { struct iovec iov; struct msghdr msg = { 0 }; uint8 cmsgBuf[CMSG_SPACE(sizeof(int))]; iov.iov_base = buf; iov.iov_len = num; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsgBuf; msg.msg_controllen = sizeof cmsgBuf; ret = recvmsg(sslSock->fd, &msg, 0); if (ret >= 0 && msg.msg_controllen != 0) { struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { int receivedFd = *(int *)CMSG_DATA(cmsg); ASSERT(*fd == -1); *fd = receivedFd; } } } } #endif return ret; }
static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf, size_t buffersize, CURLcode * curlcode) { char error_buffer[120]; /* OpenSSL documents that this must be at least 120 bytes long. */ unsigned long sslerror; int buffsize; int nread; buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; nread = SSL_Read(conn->ssl[num].handle, buf, buffsize); if(nread < 0) { /* failed SSL_read */ switch (nread) { case SSL_ERROR_BAD_STATE: /* there's data pending, re-invoke SSL_Read(). */ *curlcode = CURLE_AGAIN; return -1; case SSL_ERROR_IO: switch (errno) { case EWOULDBLOCK: *curlcode = CURLE_AGAIN; return -1; } failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno)); *curlcode = CURLE_RECV_ERROR; return -1; default: failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL)); *curlcode = CURLE_RECV_ERROR; return -1; } } return (ssize_t) nread; }
/* Read/write from/to client at the specified socket. * * ctx The SSL/TLS connection data. * threadData The SSL connection data for a thread. * sslConn The SSL connection data object. * returns EXIT_FAILURE on failure and EXIT_SUCCESS otherwise. */ static int SSLConn_ReadWrite(SSLConn_CTX* ctx, ThreadData* threadData, SSLConn* sslConn) { int ret; int len; /* Perform TLS handshake if in accept state. */ switch (sslConn->state) { case ACCEPT: ret = SSL_Accept(sslConn->ssl, &ctx->acceptTime, &ctx->resumeTime); if (ret == 0) { printf("ERROR: Accept failed\n"); SSLConn_Close(ctx, threadData, sslConn); return EXIT_FAILURE; } if (ret == 1) sslConn->state = READ; break; case READ: { char buffer[NUM_READ_BYTES]; len = ctx->bufferLen; if (ctx->maxBytes > 0) { len = min(len, ctx->maxBytes - ctx->totalReadBytes); } if (len == 0) break; /* Read application data. */ ret = SSL_Read(sslConn->ssl, buffer, len, &ctx->totalReadBytes, &ctx->readTime); if (ret == 0) { SSLConn_Close(ctx, threadData, sslConn); return EXIT_FAILURE; } } if (ret != 1) break; sslConn->state = WRITE; case WRITE: len = ctx->replyLen; if (ctx->maxBytes > 0) { len = min(len, ctx->maxBytes - ctx->totalWriteBytes); } if (len == 0) break; /* Write application data. */ ret = SSL_Write(sslConn->ssl, reply, len, &ctx->totalWriteBytes, &ctx->writeTime); if (ret == 0) { printf("ERROR: Write failed\n"); SSLConn_Close(ctx, threadData, sslConn); return EXIT_FAILURE; } if (ret == 1) sslConn->state = READ; break; case CLOSED: break; } return EXIT_SUCCESS; }
HRESULT Library_spot_net_security_native_Microsoft_SPOT_Net_Security_SslNative::ReadWriteHelper( CLR_RT_StackFrame& stack, bool isWrite ) { NATIVE_PROFILE_CLR_NETWORK(); TINYCLR_HEADER(); CLR_RT_HeapBlock* socket = stack.Arg0().Dereference(); CLR_RT_HeapBlock_Array* arrData = stack.Arg1().DereferenceArray(); CLR_INT32 offset = stack.Arg2().NumericByRef().s4; CLR_INT32 count = stack.Arg3().NumericByRef().s4; CLR_INT32 timeout_ms = stack.Arg4().NumericByRef().s4; CLR_UINT8* buffer; CLR_RT_HeapBlock hbTimeout; CLR_INT32 totReadWrite; bool fRes = true; CLR_INT64 *timeout; int result = 0; CLR_INT32 handle; if(count == 0) { stack.SetResult_I4( 0 ); TINYCLR_SET_AND_LEAVE(S_OK); } FAULT_ON_NULL(socket); handle = socket[ Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::FIELD__m_Handle ].NumericByRef().s4; /* Because we could have been a rescheduled call due to a prior call that would have blocked, we need to see * if our handle has been shutdown before continuing. */ if (handle == Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::DISPOSED_HANDLE) { ThrowError( stack, CLR_E_OBJECT_DISPOSED ); TINYCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION); } FAULT_ON_NULL(arrData); hbTimeout.SetInteger( timeout_ms ); TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout )); // // Push "totReadWrite" onto the eval stack. // if(stack.m_customState == 1) { stack.PushValueI4( 0 ); stack.m_customState = 2; } totReadWrite = stack.m_evalStack[ 1 ].NumericByRef().s4; buffer = arrData->GetElement( offset + totReadWrite ); count -= totReadWrite; if((offset + count + totReadWrite) > (int)arrData->m_numOfElements) TINYCLR_SET_AND_LEAVE(CLR_E_INDEX_OUT_OF_RANGE); while(count > 0) { // first make sure we have data to read or ability to write while(fRes) { if(!isWrite) { // check SSL_DataAvailable() in case SSL has already read and buffered socket data result = SSL_DataAvailable(handle); if((result > 0) || ((result < 0) && (SOCK_getlasterror() != SOCK_EWOULDBLOCK))) { break; } } result = Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::Helper__SelectSocket( handle, isWrite ? 1 : 0 ); if((result > 0) || ((result < 0) && (SOCK_getlasterror() != SOCK_EWOULDBLOCK))) { break; } // non-blocking - allow other threads to run while we wait for socket activity TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes )); // timeout expired if(!fRes) { result = SOCK_SOCKET_ERROR; ThrowError(stack, SOCK_ETIMEDOUT); TINYCLR_SET_AND_LEAVE( CLR_E_PROCESS_EXCEPTION ); } } // socket is in the excepted state, so let's bail out if(SOCK_SOCKET_ERROR == result) { break; } if(isWrite) { result = SSL_Write( handle, (const char*)buffer, count ); } else { result = SSL_Read( handle, (char*)buffer, count ); if(result == SSL_RESULT__WOULD_BLOCK) { continue; } } // ThrowOnError expects anything other than 0 to be a failure - so return 0 if we don't have an error if(result <= 0) { break; } buffer += result; totReadWrite += result; count -= result; // read is non-blocking if we have any data if(!isWrite && (totReadWrite > 0)) { break; } stack.m_evalStack[ 1 ].NumericByRef().s4 = totReadWrite; } stack.PopValue(); // totReadWrite stack.PopValue(); // Timeout if(result < 0) { TINYCLR_CHECK_HRESULT(ThrowOnError( stack, result )); } stack.SetResult_I4( totReadWrite ); TINYCLR_NOCLEANUP(); }
/* Read/write from/to server at the specified socket. * * ctx The SSL/TLS connection data. * sslConn The SSL connection. * returns EXIT_FAILURE on failure and EXIT_SUCCESS otherwise. */ static int SSLConn_ReadWrite(SSLConn_CTX* ctx, SSLConn* sslConn) { int ret = 0; int len; switch (sslConn->state) { case INIT: case CLOSE: break; /* Perform TLS handshake. */ case CONNECT: ret = SSL_Connect(sslConn->ssl, ctx->resume, sslConn->session, &ctx->connTime, &ctx->resumeTime); if (ret == 0) { sslConn->state = CLOSE; return EXIT_FAILURE; } if (ret == 1) { sslConn->state = WRITE; } break; case WRITE: len = ctx->replyLen; if (ctx->maxBytes > 0) { len = min(len, ctx->maxBytes - ctx->totalWriteBytes); } /* Don't write if we are done. */ if (len == 0) break; /* Write application data. */ ret = SSL_Write(sslConn->ssl, ctx->reply, len, &ctx->totalWriteBytes, &ctx->writeTime); if (ret == 0) { sslConn->state = CLOSE; return EXIT_FAILURE; } if (ret == 1) sslConn->state = READ_WAIT; break; case READ_WAIT: ret = TCP_Select(sslConn->sockfd, 0); if (ret != 1) break; sslConn->state = READ; case READ: len = ctx->bufferLen; if (ctx->maxBytes > 0) { len = min(len, ctx->maxBytes - ctx->totalReadBytes); } /* Don't read if we are done. */ if (len == 0) break; /* Read application data. */ ret = SSL_Read(sslConn->ssl, ctx->buffer, len, &ctx->totalReadBytes, &ctx->readTime); if (ret == 0) { sslConn->state = CLOSE; return EXIT_FAILURE; } if (ret == 1) { if (ctx->maxConnections > 0) sslConn->state = CLOSE; else sslConn->state = WRITE; } break; } sslConn->err = ret; return EXIT_SUCCESS; }