Esempio n. 1
0
static ssize_t qsossl_send(struct connectdata * conn, int sockindex,
                           const void * mem, size_t len, CURLcode * curlcode)

{
  /* SSL_Write() is said to return 'int' while write() and send() returns
     'size_t' */
  int rc;

  rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);

  if(rc < 0) {
    switch(rc) {

    case SSL_ERROR_BAD_STATE:
      /* The operation did not complete; the same SSL I/O function
         should be called again later. This is basically an EWOULDBLOCK
         equivalent. */
      *curlcode = CURLE_AGAIN;
      return -1;

    case SSL_ERROR_IO:
      switch (errno) {
      case EWOULDBLOCK:
      case EINTR:
        *curlcode = CURLE_AGAIN;
        return -1;
        }

      failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
      *curlcode = CURLE_SEND_ERROR;
      return -1;
    }

    /* An SSL error. */
    failf(conn->data, "SSL_Write() returned error %s",
          SSL_Strerror(rc, NULL));
    *curlcode = CURLE_SEND_ERROR;
    return -1;
  }

  return (ssize_t) rc; /* number of bytes */
}
/* 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;
}