HRESULT Library_spot_net_native_Microsoft_SPOT_Net_NetworkInformation_NetworkInterface::IPAddressFromString___STATIC__U4__STRING( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    LPCSTR szName = stack.Arg0().RecoverString();
    struct SOCK_addrinfo hints;
    struct SOCK_addrinfo* addr = NULL;     
    struct SOCK_sockaddr_in* addr_in;
    int ret;
    
    memset( &hints, 0, sizeof(hints) );

    ret = SOCK_getaddrinfo( szName, NULL, &hints, &addr );

    // getaddrinfo returns a winsock error code rather than SOCK_SOCKET_ERROR, so pass this on to the exception handling
    if(ret != 0 || addr == NULL || addr->ai_family != SOCK_AF_INET)
    {
        TINYCLR_SET_AND_LEAVE(CLR_E_FAIL);
    }

    _ASSERTE(addr->ai_addr != NULL);
    _ASSERTE(addr->ai_addrlen >= sizeof(SOCK_sockaddr_in));

    addr_in = (struct SOCK_sockaddr_in*)addr->ai_addr;

    stack.PushValue().SetInteger( (CLR_UINT32)addr_in->sin_addr.S_un.S_addr );

    TINYCLR_CLEANUP();

    if( addr ) SOCK_freeaddrinfo( addr );

    TINYCLR_CLEANUP_END();
}
HRESULT Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::getaddrinfo___STATIC__VOID__STRING__BYREF_STRING__BYREF_SZARRAY_SZARRAY_U1( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    LPCSTR szName = stack.Arg0().RecoverString();
    struct SOCK_addrinfo hints;
    struct SOCK_addrinfo* addr = NULL;
    struct SOCK_addrinfo* addrT;
    CLR_UINT32        cAddresses = 0;
    CLR_RT_HeapBlock* pAddress;
    CLR_INT32         timeout_ms = 30000;
    CLR_RT_HeapBlock  hbTimeout;
    CLR_INT32         ret;
    bool              fRes = true;
    CLR_INT64*        timeout;

    hbTimeout.SetInteger( timeout_ms );

    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    do
    {
        memset( &hints, 0, sizeof(hints) );

        ret = SOCK_getaddrinfo( szName, NULL, &hints, &addr );

        if(ret == SOCK_SOCKET_ERROR)
        {
            if(SOCK_getlasterror() == SOCK_EWOULDBLOCK)
            {
                // 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 ));
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
    while(fRes);
    
    // timeout expired
    if(!fRes)
    {
        ret = SOCK_SOCKET_ERROR;
        
        ThrowError( stack, SOCK_ETIMEDOUT );
    
        TINYCLR_SET_AND_LEAVE( CLR_E_PROCESS_EXCEPTION );
    }

    // getaddrinfo returns a winsock error code rather than SOCK_SOCKET_ERROR, so pass this on to the exception handling
    if(ret != 0)
    {
        ThrowError( stack, ret );
        TINYCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION);
    }

    {
        CLR_RT_HeapBlock  hbCanonicalName;
        CLR_RT_HeapBlock  hbAddresses;
        
        hbCanonicalName.SetObjectReference( NULL );
        CLR_RT_ProtectFromGC gc( hbCanonicalName );

        hbAddresses.SetObjectReference( NULL );
        CLR_RT_ProtectFromGC gc2( hbAddresses );

        for(int pass = 0; pass < 2; pass++)
        {                                    
            cAddresses = 0;

            for(addrT = addr; addrT != NULL; addrT = addrT->ai_next)
            {
                if(pass == 1)
                {
                    if(addrT->ai_canonname && addrT->ai_canonname[ 0 ])
                    {
                        //allocate return string
                        TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance( hbCanonicalName, addrT->ai_canonname ));
                        TINYCLR_CHECK_HRESULT(hbCanonicalName.StoreToReference( stack.Arg1(), 0 ));
                    }

                    //allocate address and store into array
                    pAddress = (CLR_RT_HeapBlock*)hbAddresses.DereferenceArray()->GetElement( cAddresses );

                    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( *pAddress, (CLR_UINT32)addrT->ai_addrlen, g_CLR_RT_WellKnownTypes.m_UInt8 ));

                    //copy address.
                    memcpy( pAddress->DereferenceArray()->GetFirstElement(), addrT->ai_addr, addrT->ai_addrlen );
                }
                                
                cAddresses++;
            }
                            
            if(pass == 0)
            {
                //allocate array of byte arrays
                CLR_RT_ReflectionDef_Index idx;

                idx.m_kind               = REFLECTION_TYPE;
                idx.m_levels             = 2;
                idx.m_data.m_type.m_data = g_CLR_RT_WellKnownTypes.m_UInt8.m_data;

                TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( hbAddresses, cAddresses, idx ));

                TINYCLR_CHECK_HRESULT(hbAddresses.StoreToReference( stack.Arg2(), 0 ));                
            }
        }    
    }

    stack.PopValue();       // Timeout
    
    TINYCLR_CLEANUP();

    if( addr ) SOCK_freeaddrinfo( addr );

    TINYCLR_CLEANUP_END();
}
void Test_OpenSSL_ClientServerAuth()
{
    LCD_Clear();
    lcd_printf("Testing SSL Client/Server negotiations...\n");
	int err;
	int client_numbytes, server_numbytes;
	int listen_sd;
	int server_sd;
	int client_sd;
	struct TINYCLR_SSL_SOCKADDR_IN sa_serv;
	struct TINYCLR_SSL_SOCKADDR_IN sa_cli;
	size_t client_len;
	SSL_CTX* server_ctx = NULL;
	SSL*     server_ssl = NULL;
	X509*    server_cert = NULL;
	SSL_CTX* client_ctx = NULL;
	SSL*     client_ssl = NULL;
	X509*    client_cert = NULL;
	char*    str = NULL;
	char     client_buf [256];
	char	 server_buf [256];
	SSL_METHOD *server_meth = NULL;
	SSL_METHOD *client_meth = NULL;
	BIO *cert = NULL;
	X509 *x = NULL;
	EVP_PKEY *pkey = NULL;

	// SSL preliminaries. 
	// create client ssl
	client_meth = (SSL_METHOD*)SSLv3_client_method();
	client_ctx = SSL_CTX_new (client_meth);
	if (!client_ctx) goto cleanup;

	server_meth = (SSL_METHOD*)SSLv3_server_method();
	server_ctx = SSL_CTX_new (server_meth);
	if (!server_ctx) goto cleanup;

	
	if ((cert=BIO_new(BIO_s_mem())) == NULL)
	{
		TINYCLR_SSL_PRINTF("Unable to create new BIO");
		goto cleanup;
	}
	BIO_puts(cert,server_pem);
	x=PEM_read_bio_X509_AUX(cert, NULL, 0, NULL);
	
	pkey=PEM_read_bio_PrivateKey(cert,NULL,
		server_ctx->default_passwd_callback,server_ctx->default_passwd_callback_userdata);
	//if (SSL_CTX_use_certificate_file(server_ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
	if (SSL_CTX_use_certificate(server_ctx, x) <= 0) 
	{ 
		TINYCLR_SSL_PRINTF("Use certifcate chain file failed");
		goto cleanup;
	}
	if (SSL_CTX_use_PrivateKey(server_ctx, pkey) <= 0) 
	{
		TINYCLR_SSL_PRINTF("Unable to use Private Key");
		goto cleanup;
	}

	if (!SSL_CTX_check_private_key(server_ctx)) {
		TINYCLR_SSL_PRINTF("Private key does not match the certificate public key\n");
		goto cleanup;
	}

	//if (SSL_CTX_set_cipher_list(server_ctx, );

	// ----------------------------------------------- 
	// Prepare TCP socket for receiving connections

	listen_sd = TINYCLR_SSL_SOCKET (AF_INET, SOCK_STREAM, IPPROTO_TCP);   
	if (listen_sd < 0) goto cleanup;

	// set it to non-blocking
	int nonblock = 1;
	err = TINYCLR_SSL_IOCTL(listen_sd,SOCK_FIONBIO,&nonblock);
	if (err < 0)
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Nonblocking call failed for server: %d.\n", wsa);
		goto cleanup;
	}

	TINYCLR_SSL_MEMSET(&sa_serv, '\0', sizeof(sa_serv));
	sa_serv.sin_family      		= AF_INET;
	sa_serv.sin_addr.S_un.S_addr 	= inet_addr("127.0.0.1");
	sa_serv.sin_port        		= TINYCLR_SSL_HTONS (1111);          /* Server Port number */

	TINYCLR_SSL_PRINTF("Binding to %d...\n", TINYCLR_SSL_NTOHS(sa_serv.sin_port));
	err = TINYCLR_SSL_BIND(listen_sd, (struct TINYCLR_SSL_SOCKADDR*) &sa_serv,
	     sizeof (sa_serv));                   

	if (err < 0)
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Bind Socket error %d\n", wsa);
		goto cleanup;
	}

	TINYCLR_SSL_PRINTF("Listening...\n");
	/* Receive a TCP connection. */     
	err = TINYCLR_SSL_LISTEN (listen_sd, 5);                    
	if (err < 0) 
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Listen Socket error %d\n", wsa);
		goto cleanup;
	}

	// create a client socket
	client_sd = TINYCLR_SSL_SOCKET (AF_INET, SOCK_STREAM, IPPROTO_TCP);   
	if (client_sd < 0) goto cleanup;

	// set it to non-blocking
	err = TINYCLR_SSL_IOCTL(client_sd,SOCK_FIONBIO,&nonblock);
	if (err < 0)
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Nonblocking call failed for client: %d.\n", wsa);
		goto cleanup;
	}
	// Set up a tcp connection for client: Bind, Connect
	err == TINYCLR_SSL_CONNECT( client_sd, (const struct TINYCLR_SSL_SOCKADDR*)&sa_serv, sizeof(sa_serv));
	if (err < 0)
	{
		int wsa = TINYCLR_SSL_GETLASTSOCKETERROR();
		TINYCLR_SSL_PRINTF("Client connect failed with: %d.\n", wsa);
	}

	
	client_len = sizeof(sa_cli);
	char nodename[128] = "";
	char servname[128] = "";
	SOCK_addrinfo hints;
	SOCK_addrinfo *res = NULL;
	
	TINYCLR_SSL_MEMSET(&hints, '\0', sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

	SOCK_getaddrinfo(nodename,servname,&hints,&res);

	SOCK_addrinfo *ptr = NULL;
	for (ptr=res; ptr!=NULL; ptr=ptr->ai_next)
	{	
		struct sockaddr_in *ip = (struct sockaddr_in*) ptr->ai_addr;
		TINYCLR_SSL_PRINTF("Accepting connections on...%s:%d\n", 
			inet_ntoa(ip->sin_addr), 1111 );
	}

	int counter=0;
	do
	{
		server_sd = TINYCLR_SSL_ACCEPT (listen_sd, (struct TINYCLR_SSL_SOCKADDR*) &sa_cli, (int*)&client_len);
        Events_WaitForEvents(0,2000);
		TINYCLR_SSL_PRINTF("Accept again %d:%d\n", TINYCLR_SSL_GETLASTSOCKETERROR(), counter++);
	} while (server_sd == -1);
	
	TINYCLR_SSL_CLOSESOCKET (listen_sd);

	TINYCLR_SSL_PRINTF ("Connection from %lx, port %x\n",
	sa_cli.sin_addr.S_un.S_addr, sa_cli.sin_port);


	// connections are completed between server & client
	// now lets do the SSL negotiations
	// create server ssl
	server_ssl = SSL_new(server_ctx);
	if (server_ssl == NULL) goto cleanup;
	SSL_set_fd (server_ssl, server_sd);

	//Create server bio and set as non-blocking
	BIO* server_bio = BIO_new(BIO_s_socket());
	if (server_bio == NULL) goto cleanup;
	//CHK_NULL(bio);
	BIO_set_nbio(server_bio,1);
	BIO_set_fd(server_bio, server_sd, BIO_NOCLOSE);
	SSL_set_bio(server_ssl,server_bio,server_bio);

	// create client ssl & connect
	client_ssl = SSL_new(client_ctx);
	if (client_ssl == NULL) goto cleanup;
	SSL_set_fd(client_ssl, client_sd);

	//Create client bio and set as non-blocking
	BIO* client_bio = BIO_new(BIO_s_socket());
	if (client_bio == NULL) goto cleanup;
	BIO_set_nbio(client_bio,1);
	BIO_set_fd(client_bio, client_sd, BIO_NOCLOSE);
	SSL_set_bio(client_ssl,client_bio,client_bio);

	
	
	// loop until server accepts ssl client connect
	int ssl_err =0;
	do
	{
		err = SSL_connect(client_ssl);
		if (err <= 0) 
		{
			ssl_err = SSL_get_error(client_ssl,err);
			TINYCLR_SSL_PRINTF("SSL_Connect error: %d\n", ssl_err);
		}
        Events_WaitForEvents(0,1000);
		err = SSL_accept (server_ssl);
		if (err <= 0) 
		{
			ssl_err = SSL_get_error(server_ssl, err);
			TINYCLR_SSL_PRINTF("SSL_Accept error: %d\n", ssl_err);
		}
        Events_WaitForEvents(0,1000);
	} while (err != 1);

	//Get the cipher - opt
	TINYCLR_SSL_PRINTF("SSL connection using %s\n", SSL_get_cipher (server_ssl));

	//Get client's certificate (note: beware of dynamic allocation) - opt
	client_cert = SSL_get_peer_certificate (server_ssl);
	if (client_cert != NULL) 
	{
		TINYCLR_SSL_PRINTF("Client certificate:\n");

		str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
		if (str == NULL) goto cleanup;

		TINYCLR_SSL_PRINTF("subject: %s\n", str);
		OPENSSL_free (str);

		str = X509_NAME_oneline (X509_get_issuer_name  (client_cert), 0, 0);
		if (str == NULL) goto cleanup;
		TINYCLR_SSL_PRINTF("issuer: %s\n", str);
		OPENSSL_free (str);

		//We could do all sorts of certificate verification stuff here before
		//   deallocating the certificate.

		X509_free (client_cert);
	} 
	else
		TINYCLR_SSL_PRINTF("Client does not have certificate.\n");
	
	//Get server's certificate (note: beware of dynamic allocation) - opt
	server_cert = SSL_get_peer_certificate (client_ssl);
	if (server_cert != NULL) 
	{
		TINYCLR_SSL_PRINTF("Server certificate:\n");

		str = X509_NAME_oneline (X509_get_subject_name (server_cert), 0, 0);
		if (str == NULL) goto cleanup;

		TINYCLR_SSL_PRINTF("subject: %s\n", str);
		OPENSSL_free (str);

		str = X509_NAME_oneline (X509_get_issuer_name  (server_cert), 0, 0);
		if (str == NULL) goto cleanup;
		TINYCLR_SSL_PRINTF("issuer: %s\n", str);
		OPENSSL_free (str);

		/* We could do all sorts of certificate verification stuff here before
		   deallocating the certificate. */

		X509_free (server_cert);
	} 
	else
		TINYCLR_SSL_PRINTF("Server with no certificate?!?!?.\n");

	do
	{

		// DATA EXCHANGE - Receive message and send reply. 
		err = SSL_write(client_ssl,"Hello World!",TINYCLR_SSL_STRLEN("Hello World!"));
		if (err <= 0) ssl_err = SSL_get_error(client_ssl, err);
        Events_WaitForEvents(0,1000);
		server_numbytes= SSL_read (server_ssl, server_buf, sizeof(server_buf) - 1);                   
		if (server_numbytes <= 0) 
			ssl_err = SSL_get_error(server_ssl, server_numbytes);
		else
			server_buf[server_numbytes] = '\0';
        Events_WaitForEvents(0,1000);

		err = SSL_write (server_ssl, "I hear you.", TINYCLR_SSL_STRLEN("I hear you."));  
		if (err <= 0) ssl_err = SSL_get_error(server_ssl, err);
        Events_WaitForEvents(0,1000);

		client_numbytes= SSL_read(client_ssl, client_buf, sizeof(client_buf) -1);
		if (client_numbytes <= 0) 
			ssl_err = SSL_get_error(client_ssl, client_numbytes);
		else
			client_buf[client_numbytes] = '\0';
        Events_WaitForEvents(0,1000);
		
	} while (err <= 0);

	TINYCLR_SSL_PRINTF("Server got %d chars:'%s'\n", server_numbytes, server_buf);
	TINYCLR_SSL_PRINTF("Client go %d chars:'%s'\n", client_numbytes, client_buf);
	/* Clean up. */

	cleanup:
	if (pkey) EVP_PKEY_free(pkey);
	if (cert) BIO_free(cert);
	if (x) X509_free(x);
	TINYCLR_SSL_CLOSESOCKET(server_sd);
	if (server_ssl) SSL_shutdown(server_ssl);
	if (server_ssl) SSL_free (server_ssl);
	server_ssl = NULL;
	if (server_ctx) SSL_CTX_free(server_ctx);
	server_ctx = NULL;
	TINYCLR_SSL_CLOSESOCKET(client_sd);
	if (client_ssl) SSL_shutdown(client_ssl);
	if (client_ssl) SSL_free (client_ssl);
	client_ssl = NULL;
	if (client_ctx) SSL_CTX_free(client_ctx);
	client_ctx = NULL;
}