INT32 SNTPClient::Connect()
{
    SOCK_SOCKET timeSocket = SOCK_SOCKET_ERROR;
    INT32 sockErr = 0;
    UINT32 usedServer = 0;

    // look up outstdanding queries for this set of servers
    OutstandingQuery* query = FindOutstandingConnection(m_ipAddressPrimary, m_ipAddressAlternate);
    
    if(query != NULL)
    {
        //
        // signal failed queries
        //
        if(query->IsOld()) 
        {
            query->Dispose();
            query = NULL;
        }
        else
        {
            //
            // resume old connection
            //
            
            timeSocket = query->GetSocket();
        }
    }

    if(timeSocket == SOCK_SOCKET_ERROR)
    {
        //
        // new connection
        //
        
        timeSocket = SOCK_socket(SOCK_AF_INET, SOCK_SOCK_DGRAM, SOCK_IPPROTO_UDP);

        if(timeSocket == SOCK_SOCKET_ERROR)
        {
            sockErr = SOCK_getlasterror();
            return (sockErr == 0 ? HAL_TIMESERVICE_ERROR : sockErr);
        }

        SOCK_sockaddr addr;
        SOCK_sockaddr_in* dst = (SOCK_sockaddr_in*)&addr;

        memset(dst, 0, sizeof(SOCK_sockaddr_in));
        
        dst->sin_family           = SOCK_AF_INET;
        dst->sin_port             = SOCK_htons(123);
        dst->sin_addr.S_un.S_addr = SOCK_htonl(m_ipAddressPrimary);

        usedServer = m_ipAddressPrimary;

        if(SOCK_connect(timeSocket, &addr, sizeof(addr)) == SOCK_SOCKET_ERROR && SOCK_getlasterror() != SOCK_EWOULDBLOCK) 
        {
            if(m_ipAddressAlternate != 0) 
            {
                usedServer = m_ipAddressAlternate;
        
                dst->sin_addr.S_un.S_addr = SOCK_htonl(m_ipAddressAlternate);
                if(SOCK_connect(timeSocket, &addr, sizeof(addr)) == SOCK_SOCKET_ERROR && SOCK_getlasterror() != SOCK_EWOULDBLOCK)
                {
                    sockErr = SOCK_getlasterror();
                    SOCK_close(timeSocket);
                    return (sockErr == 0 ? HAL_TIMESERVICE_ERROR : sockErr);
                }
            }
            else 
            {
                sockErr = SOCK_getlasterror();
                SOCK_close(timeSocket);
                return (sockErr == 0 ? HAL_TIMESERVICE_ERROR : sockErr);
            }
        }

        Initialize();

        int sent = SOCK_send(timeSocket, (char*)SNTPData, sizeof(SNTPData), 0);

        if(sent != sizeof(SNTPData))
        {
            sockErr = SOCK_getlasterror();
            SOCK_close(timeSocket);
            return (sockErr == 0 ? HAL_TIMESERVICE_ERROR : sockErr);
        }
    }

    // retry 10 times every time we stop by
    INT32 retry = 10;
    INT32 bytesToRead = c_SNTPDataLength;
    char* buf = (char*)SNTPData;
    while(retry-- > 0)
    {
        int read = SOCK_recv(timeSocket, buf, bytesToRead, 0);

        if(read < 0 && (sockErr = SOCK_getlasterror()) != SOCK_EWOULDBLOCK)
        {
            SOCK_close(timeSocket);

            return (sockErr == 0 ? HAL_TIMESERVICE_ERROR : sockErr);
        }
        else if(read > 0) 
        {
            bytesToRead -= read;
            if(bytesToRead <= 0) 
            {
                break;
            }
            buf += read;

            // incase we start receiving data towards the end 
            // of the retry limit.
            retry++;
        }
    }

    // if we could not finish reading, then cache and retry later
    // if we read a part of answer, then declare failure
    // in the future we could try and cope with this problem
    if(bytesToRead == c_SNTPDataLength)
    {
        //
        // if this is a new connection, get a slot
        //
        if(query == NULL) {
            query = GetQuery(usedServer, timeSocket);
        }

        return HAL_TIMESERVICE_WANT_READ_WRITE;
    }
    else if(bytesToRead > 0 && bytesToRead < c_SNTPDataLength)
    {
        if(query != NULL)
            query->Dispose();
        
        return HAL_TIMESERVICE_WANT_READ_WRITE;
    }
    else 
    {
        if(query != NULL)
        {
            query->Dispose();
            query = NULL;
        }
        else 
        {
            if( timeSocket != SOCK_SOCKET_ERROR )
            {
                SOCK_close(timeSocket);
                timeSocket = SOCK_SOCKET_ERROR;
            }
        }
    }
    
    DestinationTimestamp = Time_GetUtcTime();
     
    if( !IsResponseValid() )
    {
        if(query != NULL)
        {
            query->Dispose();
            query = NULL;
        }
        else 
        {
            if( timeSocket != SOCK_SOCKET_ERROR )
            {
                SOCK_close(timeSocket);
                timeSocket = SOCK_SOCKET_ERROR;
            }
        }

        return HAL_TIMESERVICE_ERROR;
    }

    return HAL_TIMESERVICE_SUCCESS;
}
Esempio n. 2
0
int ssl_read_internal(int socket, char* data, size_t size) {

	int rc = -1;
	MATRIXSSL_PDEBUG_ALL("size: %i\n", size);
	unsigned char *sslData;
	SSL* ssl = NULL;
	SSL_Conext* sslContext = g_SSL_Driver.GetSSLContextBySocketHandle(socket);
	if (sslContext != NULL && sslContext->SslContext != NULL) {
		ssl = (SSL*) sslContext->SslContext;
	} else {
		return SOCK_SOCKET_ERROR;
	}
	rc = handleBufferdData(sslContext, data, size);
	if (rc > 0 || rc == SOCK_SOCKET_ERROR) {
		//if data was buffered, return it and wait for next call to get new data from socket
		return rc;
	}

	int len = 0;

	len = matrixSslGetReadbuf(sslContext->SslContext, &sslData);

	int rec = SOCK_recv(sslContext->SocketHandle, (char*) sslData, len, 0);
	MATRIXSSL_PDEBUG_ALL("SOCK_recv: %i\n", rec);
	if (rec == 0) {
		return rec;
	}
	rc = matrixSslReceivedData(sslContext->SslContext, (int32) rec, &sslData,
			(uint32*) &len);
	PRINT_RETURN_VALUE(rc);
	if (rc < 0) {
		PRINT_UNEXPECTED_RETURN_VALUE(rc);
		return SOCK_SOCKET_ERROR;
	}
	MATRIXSSL_PDEBUG_ALL("matrixSslReceivedData: %i\n", len);
	if (!(rc == MATRIXSSL_APP_DATA || rc == MATRIXSSL_REQUEST_RECV
			|| rc == MATRIXSSL_REQUEST_SEND || rc == MATRIXSSL_RECEIVED_ALERT)) {
		PRINT_UNEXPECTED_RETURN_VALUE(rc);
		return SOCK_SOCKET_ERROR;
	}

	if (rc == MATRIXSSL_RECEIVED_ALERT) {
		if (len == 2) {
			unsigned char alertLevel = sslData[0];
			unsigned char alertDescription = sslData[1];
			MATRIXSSL_PDEBUG(
					"Alert: Level %i, Description: %i\n", alertLevel, alertDescription);
			if (alertDescription == SSL_ALERT_CLOSE_NOTIFY) {
				return 0;
			}
		}
		return SOCK_SOCKET_ERROR;
	} else if (rc == MATRIXSSL_REQUEST_SEND) {
		int rc = handleRequestSend(sslContext);
		if (rc == MATRIXSSL_SUCCESS) {
			return 0;
		}
		return SOCK_SOCKET_ERROR;
	} else if (rc == MATRIXSSL_APP_DATA) {
		return handleAppData(size, len, data, sslData, sslContext);

	} else {
		return SSL_RESULT__WOULD_BLOCK;
	}
	PRINT_UNEXPECTED_RETURN_VALUE(rc);
	return 0;
}
HRESULT Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::SendRecvHelper( CLR_RT_StackFrame& stack, bool fSend, bool fAddress )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_RT_HeapBlock*       socket    = stack.Arg0().Dereference();
    CLR_INT32               handle;
    CLR_RT_HeapBlock_Array* arrData   = stack.Arg1().DereferenceArray(); 
    CLR_UINT32              offset    = stack.Arg2().NumericByRef().u4;
    CLR_UINT32              count     = stack.Arg3().NumericByRef().u4;
    CLR_INT32               flags     = stack.Arg4().NumericByRef().s4;
    CLR_INT32               timeout_ms = stack.ArgN(5).NumericByRef().s4;
    CLR_RT_HeapBlock        hbTimeout;

    CLR_INT64* timeout;
    CLR_UINT8* buf;
    bool       fRes = true;
    CLR_INT32  totReadWrite;
    CLR_INT32  ret = 0;

    FAULT_ON_NULL(socket);
    handle = socket[ FIELD__m_Handle ].NumericByRef().s4;

    FAULT_ON_NULL(arrData);
    
    if(offset + count > arrData->m_numOfElements) TINYCLR_SET_AND_LEAVE(CLR_E_INDEX_OUT_OF_RANGE);    

    /* 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 == DISPOSED_HANDLE)
    {
        ThrowError( stack, CLR_E_OBJECT_DISPOSED );
        TINYCLR_SET_AND_LEAVE (CLR_E_PROCESS_EXCEPTION);
    }

    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;

    buf    = arrData->GetElement( offset + totReadWrite );
    count -= totReadWrite;

    while(count > 0)
    {
        CLR_INT32 bytes = 0;

        // first make sure we have data to read or ability to write
        while(fRes)
        {
            ret = Helper__SelectSocket( handle, fSend ? 1 : 0 );

            if(ret != 0) break;

            // non-blocking - allow other threads to run while we wait for handle activity
            TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes ));
        }

        // timeout expired
        if(!fRes)
        {
            ret = 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 == ret)
        {
            break;
        }

        if(fAddress)
        {
            struct SOCK_sockaddr addr;
            CLR_UINT32 addrLen = sizeof(addr);
            CLR_RT_HeapBlock& blkAddr = stack.ArgN( 6 );

            if(fSend)
            {
                TINYCLR_CHECK_HRESULT(MarshalSockAddress( &addr, addrLen, blkAddr ));
                
                bytes = SOCK_sendto( handle, (const char*)buf, count, flags, &addr, addrLen );
            }
            else
            {
                CLR_RT_HeapBlock* pBlkAddr = blkAddr.Dereference();
                
                TINYCLR_CHECK_HRESULT(MarshalSockAddress( &addr, addrLen, *pBlkAddr ));

                bytes = SOCK_recvfrom( handle, (char*)buf, count, flags, &addr, (int*)&addrLen );

                if(bytes != SOCK_SOCKET_ERROR)
                {
                    TINYCLR_CHECK_HRESULT(MarshalSockAddress( blkAddr, &addr, addrLen ));
                }
            }
        }
        else
        {
            if(fSend)
            {
                bytes = SOCK_send( handle, (const char*)buf, count, flags );
            }
            else
            {
                bytes = SOCK_recv( handle, (char*)buf, count, flags );
            }
        }

        // send/recv/sendto/recvfrom failed
        if(bytes == SOCK_SOCKET_ERROR)
        {
            CLR_INT32 err = SOCK_getlasterror();
            
            if(err != SOCK_EWOULDBLOCK)
            {
                ret = SOCK_SOCKET_ERROR;
                break;
            }
            
            continue;
        }
                // zero recv bytes indicates the handle has been closed.
        else if(!fSend && (bytes == 0)) 
        {
            break;
        }
        
        buf          += bytes;
        totReadWrite += bytes;
        count        -= bytes;

        stack.m_evalStack[ 1 ].NumericByRef().s4 = totReadWrite;        

        // receive returns immediately after receiving bytes.
        if(!fSend && (totReadWrite > 0))
        {
            break;
        }

    }

    stack.PopValue();       // totReadWrite
    stack.PopValue();       // Timeout
    
    TINYCLR_CHECK_HRESULT(ThrowOnError( stack, ret ));

    stack.SetResult_I4( totReadWrite );

    TINYCLR_NOCLEANUP();
}
int ssl_connect_internal(int socket, const char* szTargetHost,
		int sslContextHandle) {
	static int status = MATRIXSSL_REQUEST_SEND;
	int ret = SOCK_SOCKET_ERROR;

	int nonblock = 0;
	int done = 0;

	SSL *ssl = NULL;
	SSL_Conext* sslContext = g_SSL_Driver.GetSSLContextBySslIndex(
			sslContextHandle);
	if (sslContext != NULL && sslContext->SslContext != NULL) {
		ssl = (SSL*) sslContext->SslContext;
	} else {
		MATRIXSSL_PERROR("Context not valid\n");
		return SOCK_SOCKET_ERROR;
	}

	unsigned char *sslData;

	// WARNING - SSL_Connect is asynchronous and will be called multiple times for 1 connection, therefore
	// we only want to set the CA store on the first call (when sslData == NULL)
	//
	// The first certificate is the device's outbound certificate

	int rc = 0;
	int sent = 0;
	int len = matrixSslGetOutdata(ssl, &sslData);
	do {
		if (len > 0) //(status == MATRIXSSL_REQUEST_SEND )
				{

				ret = SOCK_TRY_AGAIN;
				sent = SOCK_send(socket, (const char *) sslData, len, 0);
				//TODO check if sent
				rc = matrixSslSentData(ssl, sent);
				done = 1;
				if (rc == MATRIXSSL_SUCCESS) {
					status = MATRIXSSL_REQUEST_RECV;

			}
		} else //if(status == MATRIXSSL_REQUEST_RECV && done == 0)
		{
			int len = 1000;
			len = matrixSslGetReadbuf(ssl, &sslData);
			len = SOCK_recv(socket, (char*) sslData, len, 0);
			ret = SOCK_TRY_AGAIN;
			if (len > 0) {
				rc = matrixSslReceivedData(ssl, (int32) len, &sslData,
						(uint32*) &len);
				if (rc == MATRIXSSL_REQUEST_RECV) {
					status = MATRIXSSL_REQUEST_RECV;
				}
				if (rc == MATRIXSSL_REQUEST_SEND) {
					status = MATRIXSSL_REQUEST_SEND;
					ret = SOCK_TRY_AGAIN;
				}
				if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
					ret = 0;
				}
			}
		}
		if (done == 0) {
			len = matrixSslGetOutdata(ssl, &sslData);
		} else {
			len = 0;
		}
	} while (len);


	g_SSL_Driver.AddSslSocketHandle(sslContextHandle, socket);


	return ret;
}