topbanner_forum
  *

avatar image

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
  • Tuesday March 19, 2024, 2:27 am
  • Proudly celebrating 15+ years online.
  • Donate now to become a lifetime supporting member of the site and get a non-expiring license key for all of our programs.
  • donate

Author Topic: Announcing with UDP in C# - Punching above my weight  (Read 16325 times)

mediaguycouk

  • Supporting Member
  • Joined in 2007
  • **
  • Posts: 247
    • View Profile
    • Mediaguy
    • Donate to Member
Announcing with UDP in C# - Punching above my weight
« on: April 27, 2011, 09:38 AM »
Hi all,
I've got a multicast IPTV system where I work and a piece of software, which no longer works in Windows 7, discovers what channels are available using SSDP. I was hoping to write a short console application that would annouce itself and then wait for replies.

My programming skills lend themselves to manipulating online examples to do what I want, but I'm having trouble finding any example code for this type of thing, this being the only example I can find - http://www.codeproje...l.aspx?display=Print . I was wondering if anyone knew of anything else out there?
Learning C# - Graham Robinson

Renegade

  • Charter Member
  • Joined in 2005
  • ***
  • Posts: 13,288
  • Tell me something you don't know...
    • View Profile
    • Renegade Minds
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #1 on: April 27, 2011, 10:17 AM »
I'm not sure I know what you're asking for.

Are you broadcasting over the LAN or WAN?

I don't know what your requirements are, but my gut is telling me that you'll need to do a significant amount of modifying.
Slow Down Music - Where I commit thought crimes...

Freedom is the right to be wrong, not the right to do wrong. - John Diefenbaker

mediaguycouk

  • Supporting Member
  • Joined in 2007
  • **
  • Posts: 247
    • View Profile
    • Mediaguy
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #2 on: April 27, 2011, 10:37 AM »
LAN.

I'm working my way through the example code I linked above and was wondering if anyone else had seen any code like it. I suppose it really was a shot in the dark.

This is the kind of code I'm after

Code: C# [Select]
  1. public static bool Discover()
  2.         {
  3.             Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  4.             s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
  5.             string req = "M-SEARCH * HTTP/1.1\r\n" +
  6.             "HOST: 239.255.255.250:1900\r\n" +
  7.             "ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n" +
  8.             "MAN:\"ssdp:discover\"\r\n" +
  9.             "MX:3\r\n\r\n";
  10.             byte[] data = Encoding.ASCII.GetBytes(req);
  11.             IPEndPoint ipe = new IPEndPoint(IPAddress.Broadcast, 1900);
  12.             byte[] buffer = new byte[0x1000];
  13.  
  14.             DateTime start = DateTime.Now;
  15.  
  16.             Console.WriteLine("Starting do while < timeout");
  17.             do
  18.             {
  19.                 s.SendTo(data, ipe);
  20.                 s.SendTo(data, ipe);
  21.                 s.SendTo(data, ipe);
  22.  
  23.                 int length = 0;
  24.                 do
  25.                 {
  26.                     length = s.Receive(buffer);
  27.                     string resp = Encoding.ASCII.GetString(buffer, 0, length).ToLower();
  28.                     Console.WriteLine(resp);
  29.                 } while (length > 0);
  30.             } while (start.Subtract(DateTime.Now) < _timeout);
  31.             return false;
  32.         }
  33. }
Learning C# - Graham Robinson

Renegade

  • Charter Member
  • Joined in 2005
  • ***
  • Posts: 13,288
  • Tell me something you don't know...
    • View Profile
    • Renegade Minds
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #3 on: April 27, 2011, 10:41 AM »
Sorry -- I'm a bottle of wine in, and off the top of my head, I'm drawing a blank.

Hopefully someone can chime in with something useful.

Check StackOverFlow. There's usually something there that's a good pointer. ;) I just struck out there with some EXIF issues, but most often they've got an answer. Just follow the links and explore a bit. You likely won't find anything to directly answer the question, but people often point to something that answers it in one way or another.
Slow Down Music - Where I commit thought crimes...

Freedom is the right to be wrong, not the right to do wrong. - John Diefenbaker

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #4 on: April 27, 2011, 11:59 AM »
If you send a packet, and then wait for a response, in the same thread ... Chances are the code will sit there forever waiting for said response.

With TCP you can call select(...) in a loop to see if the socket has become writable/readable and then do X. But if you jump straight to receive, it won't return until its buffer is full ... So if nothing is coming in ... Well...Eternity passes... :)

UDP is connectionless, so I'm not entirely sure what to use for it. In C/C++ there is recvfrom(...) what if any C# equivalent there is I don't know.

I do know you need to be sure there is something out there listening and waiting to respond, or you'll drive yourself nutz trying to debugg the protocol. I usually keep a packet sniffer running filtered down to just the test packets I'm working with. So I can try to keep track of who dropped what, why, and where.

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #5 on: April 27, 2011, 12:14 PM »
I don't know where I got these originally (it's not my code), which is unfortunate because I've screwed with them a bit. But this is a UDP client server pair written in C++ that does work that might give you some ideas on how to proceed.

* UDP Ping Pong.zip (12.65 kB - downloaded 390 times.)

mediaguycouk

  • Supporting Member
  • Joined in 2007
  • **
  • Posts: 247
    • View Profile
    • Mediaguy
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #6 on: April 27, 2011, 12:52 PM »
Thanks Joker
Learning C# - Graham Robinson

jazper

  • Coding Snacks Author
  • Charter Honorary Member
  • Joined in 2005
  • ***
  • Posts: 92
    • View Profile
    • Jazper's Software
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #7 on: April 28, 2011, 09:57 PM »
I whipped this up real fast, it ain't pretty but should work


namespace SSDPTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            UdpClient ucs = new UdpClient(12555);

            string data = "M-SEARCH * HTTP/1.1\r\n" +
                            "HOST: 239.255.255.250:1900\r\n" +
                            "ST:upnp:rootdevice\r\n" +
                            "MAN:\"ssdp:discover\"\r\n" +
                            "MX:3\r\n\r\n";
           
            Byte[] sendBytes = Encoding.ASCII.GetBytes(data);
            ucs.Connect("255.255.255.255", 1900);
            ucs.Send(sendBytes, sendBytes.Length);
            ucs.Close();

            IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
            UdpClient ucr = new UdpClient(12555);


            Byte[] receiveBytes = ucr.Receive(ref RemoteIpEndPoint);

            textBox1.Text += Encoding.ASCII.GetString(receiveBytes);

            ucr.Close();

        }
    }
}

mediaguycouk

  • Supporting Member
  • Joined in 2007
  • **
  • Posts: 247
    • View Profile
    • Mediaguy
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #8 on: May 03, 2011, 05:16 AM »
Thanks Jazper,
You code confirms what I've previously found. It seems quite easy and reliable to get the router you are connected to to respond to these types of broadcasts but the more unreliable and inconsistent IPTV systems seem to lock up the .Receive commands.

In the end I've been using Wireshark and monitoring the responses of a propriety IPTV multicast program. I then export the filtered Wireshark output into a C# application to get all the channels.

Code: C# [Select]
  1. // Please excuse the fact that I found out it was called 'Wireshark' about half way through and then
  2. // couldn't be bothered fixing the function names
  3. private void btnOpenWireShackFile_Click(object sender, EventArgs e)
  4.         {
  5.             MessageBox.Show("Remember to select the Wireshark \"K12 Text File\" that you have saved with " +
  6.                 "the filter 'sap.flags' (no apostrophes) and save \"Packet Range: Displayed\" and \"All packets\"",
  7.                 "Instructions", MessageBoxButtons.OK, MessageBoxIcon.Information);
  8.  
  9.             btnSave.Enabled = false;
  10.  
  11.             openWireshackTxtFile.Title = "Choose wireshark txt file";
  12.             openWireshackTxtFile.Filter = "TXT Files|*.txt";
  13.  
  14.             if (openWireshackTxtFile.ShowDialog(this) == DialogResult.OK)
  15.             {
  16.                 strWireSharkFileLocation = openWireshackTxtFile.FileName;
  17.  
  18.                 replaceBigTextBox("");
  19.                 replaceM3UTextBox("");
  20.  
  21.                 Thread threadReadHex = new Thread(readHexAndOutputASCII);
  22.                 threadReadHex.IsBackground = true;
  23.                 threadReadHex.Start();
  24.             }
  25.         }
  26.  
  27.         private void readHexAndOutputASCII()
  28.         {
  29.             if (strWireSharkFileLocation == "VOID")
  30.             {
  31.                 return;
  32.             }
  33.            
  34.             try
  35.             {
  36.                 strWireSharkFile = File.ReadAllLines(strWireSharkFileLocation);
  37.             }
  38.             catch
  39.             {
  40.                 MessageBox.Show("Failed to open Wireshack file", "Fatal error",
  41.                     MessageBoxButtons.OK, MessageBoxIcon.Error);
  42.                 return;
  43.             }
  44.  
  45.             replaceM3UTextBox("#EXTM3U\r\n");
  46.  
  47.             int i = 1;
  48.             int j = 0;
  49.  
  50.             foreach (string line in strWireSharkFile)
  51.             {
  52.                 if (line.Length > 2 && line.Substring(0, 2) == "|0")
  53.                 {
  54.                     string[] characters = line.Split('|');
  55.                     string completeLine = "";
  56.  
  57.                     foreach (string hex in characters)
  58.                     {
  59.                        
  60.                         if (hex.Length == 2)
  61.                         {
  62.                             try
  63.                             {
  64.                                 int n = Convert.ToInt32(hex, 16);
  65.                                 if (n >= 32 && n < 255)
  66.                                 {
  67.                                     char c = (char)n;
  68.                                     completeLine += c.ToString();
  69.                                 }
  70.                                 else if (n == 10)
  71.                                 {
  72.                                     completeLine += "|";
  73.                                 }
  74.                             }
  75.                             catch
  76.                             {
  77.                                 // Do we need to do anything here?
  78.                             }
  79.                         }
  80.                     }
  81.  
  82.                     addToBigTextBox(completeLine.Replace("|", "\r\n") + "\r\r\n");
  83.  
  84.                     string[] partLine = completeLine.Split('|');
  85.  
  86.                     foreach (string data in partLine)
  87.                     {
  88.  
  89.                         if (data.Length > 3 && data.Substring(0, 2) == "s=")
  90.                         {
  91.                             string channelName = data.Substring(2, data.Length - 2);
  92.                             addToM3UTextBox("#EXTINF:" + i + "," + channelName + "\r\n");
  93.                         }
  94.  
  95.                         if (data.Length > 3 && data.Substring(0, 2) == "c=")
  96.                         {
  97.                             string nospacedata = data.Replace(" ", "");
  98.                             string[] splitip = nospacedata.Split('/');
  99.                             string ip = splitip[0].Substring(7, splitip[0].Length - 7);
  100.                             addToM3UTextBox("udp://" + ip + ":5000" + "\r\n");
  101.                         }
  102.  
  103.                        
  104.                     }
  105.                     decimal deProgressBar = (((decimal)j + 1) / (decimal)strWireSharkFile.Length) * 100;
  106.                     intProgressBar = (int)Math.Ceiling(deProgressBar);
  107.                     changeProgressBar();
  108.                     i++;
  109.                 }
  110.                 j++;
  111.             }
  112.             intProgressBar = 100;
  113.             changeProgressBar();
  114.         }
Learning C# - Graham Robinson

Stoic Joker

  • Honorary Member
  • Joined in 2008
  • **
  • Posts: 6,646
    • View Profile
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #9 on: May 03, 2011, 06:54 AM »
the more unreliable and inconsistent IPTV systems seem to lock up the .Receive commands.
-mediaguycouk (May 03, 2011, 05:16 AM)

Hm... Sorry if I get a little Captain Obvious here, but are you sure the request packet is being replicated exactly? The header may need a bit of tweaking to get the device to respond reliably.

If you put receive in its own thread with a small buffer called in a loop you can then get partial output to display which might help to establish where it's hanging and why.

(Sorry man I got nothing in C#, but...) Here's a Quick-N-Dirty example that I cut out of a project:
Code: C++ [Select]
  1. // The thread passes a handle to the edit control to the receive function so tell us what's u.
  2.   while(WaitForSingleObject(hStopEvent, 0) != WAIT_OBJECT_0) { // ...When it's Time for it.
  3.           if(bPortChange) {
  4.                   SetEvent(hStopEvent);
  5.           }else{
  6.                   Listen4Ping(g_hEdit, s);
  7.           }
  8.   }
  9.  
  10.  //===========================================================================================
  11. //-------------------------------------------------------------+++--> Tell User What You Hear!
  12. void Listen4Ping(HWND hEdit, SOCKET soc) { //------------------------------------------+++-->
  13.         TCHAR recvbuf[MAX_BUFF] = {0};
  14.         TCHAR szTemp[GEN_BUFF] = {0};
  15.         SOCKADDR_IN saPong; // IP Address Structure for Local Listener.
  16.         int iSenderAddrSize = sizeof(saPong);
  17.         int iResult;
  18.  
  19.         timeval tv; // Time Value Object
  20.         fd_set fd; // File Descriptor Set
  21.  
  22.   fd.fd_count = 1; //----//-+++--> Number of sockets in the set.
  23.   fd.fd_array[0] = soc; // Array of sockets that are in the set.
  24.  
  25.   tv.tv_sec = 1;  // Set Timer Value to Wait Only 1 second...
  26.   tv.tv_usec = 0; // With No Additional microseconds to wait.
  27.  
  28.   iResult = select(1, &fd, NULL, NULL, &tv);
  29.  
  30.   if(iResult > 0) {
  31.           SOCKET Accpt;
  32.           int iBytesRecv;
  33.           Accpt = accept(soc,(SOCKADDR *)&saPong, &iSenderAddrSize);
  34.           StringCbPrintf(szTemp, GEN_BUFF, "\r\nConnected Client's IP: %s", inet_ntoa(saPong.sin_addr));
  35.           SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)szTemp);
  36.           iBytesRecv = recv(Accpt, recvbuf, MAX_BUFF, 0);
  37.           SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)recvbuf);
  38.           StringCbPrintf(szTemp, GEN_BUFF, "\r\nBytes Received: %ld\r\n\r\n", iBytesRecv);
  39.           SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)szTemp);
  40.           if(Accpt) closesocket(Accpt);
  41.   }else{
  42.           SendMessage(hEdit, EM_REPLACESEL, FALSE, (LPARAM)".");
  43.   }
  44. } // Here I get output of something every second regardless of a connection. That was if something does go wrong is obvious even if it isn't bad enough to lock the entire app.

mediaguycouk

  • Supporting Member
  • Joined in 2007
  • **
  • Posts: 247
    • View Profile
    • Mediaguy
    • Donate to Member
Re: Announcing with UDP in C# - Punching above my weight
« Reply #10 on: May 03, 2011, 10:42 AM »
Sorry if I get a little Captain Obvious here, but are you sure the request packet is being replicated exactly?
It's the same as the WireShark capture, but past that I can't be 100%.

I've certainly given up on this, so don't spend any more time on it. Once the announce works I've got to query the box for the channels all while programming on a subnet that doesn't actually have the boxes on it.

This project is where an attitude of 'fail quickly and adapt' is working well. The C# application to use the Wireshark data works well enough for how little it would be used.

Thanks all

Graham
Learning C# - Graham Robinson