locked
DatagramSocket write problem in C++/CX

    Question

  • Consider the following code:

    DatagramSocket^ s = ref new DatagramSocket();

    later:

    WRL::Wrappers::Event evt(CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS));
    HRESULT hr = 0;
    
    auto operation = s->ConnectAsync(host, service);
                            
    operation->Completed = ref new AsyncActionCompletedHandler(
        [&evt, &hr](IAsyncAction^ asyncInfo)
        {
            hr = asyncInfo->ErrorCode.Value;
            SetEvent(evt.Get());
        }, Platform::CallbackContext::Any);
    
    operation->Start();
                
    WaitForSingleObjectEx(evt.Get(), INFINITE, FALSE);
                
    assert (hr == 0);
    
    

    Datagram socket is now associated with host:service, so we send data:

    IOutputStream^ os = s->OutputStream;
    
    DataWriter^ writer = ref new DataWriter(os);
    
    array<unsigned char>^ data = ref new array<unsigned char>(len);
    ::memcpy(data->Data, buf, len);
    
    writer->WriteBytes(data);
    
    auto operation = writer->StoreAsync();
    
    WRL::Wrappers::Event evt(CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS));
    HRESULT hr = 0;
    
    operation->Completed = ref new AsyncOperationCompletedHandler<UINT32>(
    	[&evt, &hr](IAsyncOperation<UINT32>^ op)
        {
            hr = op->ErrorCode.Value;                    
            SetEvent(evt.Get());
        }, Platform::CallbackContext::Any);
    
    operation->Start();
    
    WaitForSingleObjectEx(evt.Get(), INFINITE, FALSE);
                
    // We never get here
    

    And the delegate is never called. If i skip the connect part then delegate will be called here indicating an error which is correct behavior. The problem is in the "success" case, the delegate isn't called so I can't find out if write operations succeeded or not and also, what happens with the delegate, does it get deallocated or its memory is leaked or what ? Note that this only happens in C++/CX, in JavaScript the very same code works fine... Is this a bug in WinRT, C++/CX ?

    Friday, January 27, 2012 1:12 PM

All replies

  • Ok, worked around the problem like this:
    DataWriter^ writer = ref new DataWriter();
    
    array<unsigned char>^ data = ref new array<unsigned char>(len);
    ::memcpy(data->Data, buf, len);
    
    writer->WriteBytes(data);
    
    auto operation = os->WriteAsync(writer->DetachBuffer());
    
    WRL::Wrappers::Event evt(CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS));
    HRESULT hr = 0;
    
    operation->Completed = ref new AsyncOperationWithProgressCompletedHandler<UINT32, UINT32>(
    	[&evt, &hr](IAsyncOperationWithProgress<UINT32, UINT32>^ op)
        {
            hr = op->ErrorCode.Value;
            SetEvent(evt.Get());                    
        }, Platform::CallbackContext::Any);
    
    operation->Start();
    

    'hr' is 0 and op->GetResults() returns 'len', but the datagram still doesn't reach the other end. I've also tried calling os->FlushAsync() - no luck...
    I've also tried replacing os = s->OutputStream with os = s->GetOutputStream(ref new HostName(ref new Platform::String(host_name)), ref new Platform::String(service_name)) - no luck...
    Friday, January 27, 2012 2:49 PM
  • Ok, the datagram is being sent (Wireshark shows it), but is not received by the other side, the delegate:

    s->MessageReceived += ref new DatagramSocketMessageReceivedEventHandler(
        []( DatagramSocket^ sender,
                DatagramSocketMessageReceivedEventArgs^ e )
        {
            ...
        });
    

    isn't called. The socket on the other side is bound using:

    s->Information->LocalHostName = host; // "127.0.0.1"<br/>s->Information->LocalServiceName = service; // "9124"
    
    auto operation = s->BindServiceNameAsync();
    
    WRL::Wrappers::Event evt(CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS));
    HRESULT hr = 0;
                
    operation->Completed = ref new AsyncActionCompletedHandler(
        [&evt, &hr](IAsyncAction^ asyncInfo)
        {
            hr = asyncInfo->ErrorCode.Value;
            SetEvent(evt.Get());                    
        }, Platform::CallbackContext::Any);
    
    operation->Start();
    
    WaitForSingleObjectEx(evt.Get(), INFINITE, FALSE);
                
    assert (hr == 0);
    

    Another important thing to note, output of "netstat -p udp -a" is:

      Proto  Local Address          Foreign Address        State
      UDP    0.0.0.0:9124           *:*
    Inspite of the fact that socket was bound to "127.0.0.1", "127.0.0.1" is not the same as "0.0.0.0", it's very important for my application to bind a socket to "127.0.0.1" so it wouldn't receive datagrams from other computers on the network. How can I bind to "127.0.0.1" and why doesn't my app receive datagrams, it did bind to "0.0.0.0", so it must receive datagrams coming from all interfaces on port 9124...

    Friday, January 27, 2012 3:36 PM
  • What was the resolution to this?
    Wednesday, August 1, 2012 9:40 AM