Arduino Forum

Using Arduino => Networking, Protocols, and Devices => Topic started by: zimm0who0net on Apr 25, 2013, 09:18 pm

Title: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 25, 2013, 09:18 pm
So here's the issue.  If I use any of the 4 W5100 sockets as at TCP socket that sends/receives data, it seems to disqualify that socket from sending out UDP datagrams anymore.  Calling a W5100.init() seems to fix the issue, but of course that resets all of my sockets.
Has anyone experienced this before? 
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 25, 2013, 10:34 pm
So I've dummied up a test case from some of the Arduino samples.  All this does is create a TCP server on port 80, and every 10 seconds it'll poll an NTP server via UDP.  Here's what will happen:
* It'll start listening on port 80 (W5100 socket #0)
* It'll do the NTP stuff from port 8888 on W5100 socket #1.  (this works fine).
* It'll continue to do the NTP stuff every 10 seconds indefinitely and successfully.
* If you connect to the port 80 (e.g. browse there with a web server), it'll service the request on socket 0, and open a new listening port on socket 1, and then terminate socket 0.
* The NTP stuff continues every 10 seconds, but this time it's on socket 0.  It works..
* Browse to port 80 again.  This time it'll service on socket 1.
* NTP never works again.  Web server works just fine forever...

Here's the sketch.
Code: [Select]
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <utility/W5100.h>

void ShowSockStatus()
{
for (int i = 0; i < MAX_SOCK_NUM; i++) {
Serial.print("Socket#");
Serial.print(i);
uint8_t s = W5100.readSnSR(i);
Serial.print(":0x");
Serial.print(s,16);
Serial.print(" ");
Serial.print(W5100.readSnPORT(i));
Serial.print(" D:");
uint8_t dip[4];
W5100.readSnDIPR(i, dip);
for (int j=0; j<4; j++) {
Serial.print(dip[j],10);
if (j<3) Serial.print(".");
}
Serial.print("(");
Serial.print(W5100.readSnDPORT(i));
Serial.println(")");
}
}

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

EthernetServer server(80);
IPAddress timeServer(192,168,10,1);
IPAddress ip(192,168,10,20);
IPAddress gateway(192,168,10, 2);
IPAddress subnet(255, 255, 255, 0);

long timer;

void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip, INADDR_NONE, gateway, subnet);
delay(500);

Serial.println("Start!");
server.begin();
ShowSockStatus();
timer = millis();
}

const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(EthernetUDP & Udp, IPAddress& address)
{

// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011;   // LI, Version, Mode
packetBuffer[1] = 0;     // Stratum, or type of clock
packetBuffer[2] = 6;     // Polling Interval
packetBuffer[3] = 0xEC;  // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12]  = 49;
packetBuffer[13]  = 0x4E;
packetBuffer[14]  = 49;
packetBuffer[15]  = 52;

// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:    
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer,NTP_PACKET_SIZE);
Udp.endPacket();
}

void checkTime()
{
EthernetUDP Udp;
Udp.begin(8888);
sendNTPpacket(Udp, timeServer); // send an NTP packet to a time server
Serial.println("");
ShowSockStatus();
// wait to see if a reply is available
delay(1000); 
if ( Udp.parsePacket() ) { 
// We've received a packet, read the data from it
Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); 
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord; 

// now convert NTP time into everyday time:
Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;     
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears; 
// print Unix time:
Serial.println(epoch); 

else
Serial.println("UDP FAIL!");
Udp.stop();

}

void loop()
{
//Check if a web client has attached.
EthernetClient client = server.available();
if (client) {
Serial.println("new Client");
ShowSockStatus();
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.print(c);
if (c == '\n' && currentLineIsBlank) {
client.stop();
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}

if ((millis() - timer) > 10000) {
timer = millis();
checkTime();
}
}
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 26, 2013, 12:54 pm
I loaded up your sketch and tested it. I changed only the network settings and the NTP server ip since I have my own NTP server here. It works ok, except the webpage says "No data received". I made several requests, and the NTP client is still running fine.

For those Linux users out there, you must change this include.
#include <utility/W5100.h>
to
#include <utility/w5100.h>
File names are case sensitive in linux.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 26, 2013, 04:37 pm
How very strange.  I'm using 1.0.4 also.  I've verified this on two different Ethernet Shields and a bunch of different Megas and Unos.  I wonder if there were different versions of the W5100 chip released?  What output do you get? 

Here's mine:
Code: [Select]
Start!
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 0 D:0.0.0.0(0)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)

Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Unix time = 1366986649

Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Unix time = 1366986659

Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Unix time = 1366986669
new Client
Socket#0:0x17 80 D:192.168.10.213(9129)
Socket#1:0x14 80 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.10.20
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
If-Modified-Since: Fri, 02 Jun 2006 09:46:32 GMT

client disconnected

Socket#0:0x22 8888 D:192.168.10.1(123)
Socket#1:0x14 80 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Unix time = 1366986679
new Client
Socket#0:0x14 80 D:192.168.10.1(123)
Socket#1:0x17 80 D:192.168.10.213(9132)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.10.20
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected

Socket#0:0x14 80 D:192.168.10.1(123)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
UDP FAIL!

Socket#0:0x14 80 D:192.168.10.1(123)
Socket#1:0x22 8888 D:192.168.10.1(123)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
UDP FAIL!


Once it goes into fail mode it'll never come back **for that socket**.  However, if you play around with refreshing your browser you can sometimes get it to bounce to a different socket and then it'll work.  (at least until that socket also has had a TCP conversation on it)  I've also verified through tcpdump packet capture that the packet doesn't actually get sent. 
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 26, 2013, 05:25 pm
This worked for me. You did have some errors in that code that did not manifest themselves first pass, but did on a second. I moved the Udp.begin() to setup() and commented out the Udp.stop(). I also used my server code.
Code: [Select]
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <utility/w5100.h>

void ShowSockStatus()
{
for (int i = 0; i < MAX_SOCK_NUM; i++) {
Serial.print("Socket#");
Serial.print(i);
uint8_t s = W5100.readSnSR(i);
Serial.print(":0x");
Serial.print(s,16);
Serial.print(" ");
Serial.print(W5100.readSnPORT(i));
Serial.print(" D:");
uint8_t dip[4];
W5100.readSnDIPR(i, dip);
for (int j=0; j<4; j++) {
Serial.print(dip[j],10);
if (j<3) Serial.print(".");
}
Serial.print("(");
Serial.print(W5100.readSnDPORT(i));
Serial.println(")");
}
}

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

EthernetServer server(80);
IPAddress timeServer(198,55,111,50);

IPAddress ip(192,168,2,2);
IPAddress gateway(192,168,2, 1);
IPAddress subnet(255, 255, 255, 0);

long timer;
EthernetUDP Udp;

void setup() {
Serial.begin(9600);

        pinMode(4, OUTPUT);
        digitalWrite(4, HIGH);
       
Ethernet.begin(mac, ip, INADDR_NONE, gateway, subnet);
delay(500);
Udp.begin(8888);

Serial.println("Start!");
server.begin();
ShowSockStatus();
timer = millis();
}

const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(EthernetUDP & Udp, IPAddress& address)
{

// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011;   // LI, Version, Mode
packetBuffer[1] = 0;     // Stratum, or type of clock
packetBuffer[2] = 6;     // Polling Interval
packetBuffer[3] = 0xEC;  // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12]  = 49;
packetBuffer[13]  = 0x4E;
packetBuffer[14]  = 49;
packetBuffer[15]  = 52;

// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:    
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer,NTP_PACKET_SIZE);
Udp.endPacket();
}

void checkTime()
{
sendNTPpacket(Udp, timeServer); // send an NTP packet to a time server
Serial.println("");
ShowSockStatus();
// wait to see if a reply is available
delay(1000); 
if ( Udp.parsePacket() ) { 
// We've received a packet, read the data from it
Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); 
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord; 

// now convert NTP time into everyday time:
Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;     
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears; 
// print Unix time:
Serial.println(epoch); 

else
Serial.println("UDP FAIL!");
// Udp.stop();

}

void loop()
{
//Check if a web client has attached.
        checkServer();
       
if ((millis() - timer) > 10000) {
timer = millis();
checkTime();
}
}


void checkServer()
{
  EthernetClient client = server.available();
  if(client) {
    boolean currentLineIsBlank = true;
    boolean currentLineIsGet = true;
    int tCount = 0;
    char tBuf[64];
    int r,t;
    char *pch;

    Serial.print(F("Client request: "));

    // this controls the timeout
    int loopCount = 0;

    while (client.connected()) {
      while(client.available()) {
        // if packet, reset loopCount
        loopCount = 0;
        char c = client.read();

        if(currentLineIsGet && tCount < 63)
        {
          tBuf[tCount] = c;
          tCount++;
          tBuf[tCount] = 0;         
        }

        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response
          Serial.println(tBuf);
          Serial.print(F("POST data: "));
          while(client.available()) Serial.write(client.read());
          Serial.println();

          pch = strtok(tBuf,"?");

          while(pch != NULL)
          {
            if(strncmp(pch,"t=",2) == 0)
            {
              t = atoi(pch+2);
              Serial.print("t=");
              Serial.println(t,DEC);             
            }

            if(strncmp(pch,"r=",2) == 0)
            {
              r = atoi(pch+2);
              Serial.print("r=");             
              Serial.println(r,DEC);
            }


            pch = strtok(NULL,"& ");
          }
          Serial.println(F("Sending response"));
          client.print(F("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<html>"));
          client.println(F("<body><H1>TEST</H1>"));
          client.println(F("<form method=GET>T: <input type=text name=t><br>"));
          client.println(F("R: <input type=text name=r><br><input type=submit></form>"));


          client.println(F("</body></html>"));
          client.stop();
        }
        else if (c == '\n') {
          currentLineIsBlank = true;
          currentLineIsGet = false;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }

      loopCount++;

      // if 10000ms has passed since last packet
      if(loopCount > 10000) {
        // close connection
        client.stop();
        Serial.println("\r\nTimeout");
      }

      // delay 1ms for timeout timing
      delay(1);
    }
    Serial.println(F("done"));
  }
}
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 26, 2013, 05:31 pm
Here is the serial monitor for that:
Quote
Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x14 80 D:192.168.1.254(3287)
Socket#2:0x0 80 D:192.168.1.254(3286)
Socket#3:0x0 80 D:192.168.1.254(3290)
Unix time = 1366989984
Client request: GET /?t=&r= HTTP/1.1

POST data:
t=0
r=0
Sending response
done
Client request: GET /favicon.ico HTTP/1.1

POST data:
Sending response
done

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x14 80 D:192.168.1.254(3291)
Socket#2:0x0 80 D:192.168.1.254(3292)
Socket#3:0x0 80 D:192.168.1.254(3290)
Unix time = 1366989994

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x14 80 D:192.168.1.254(3291)
Socket#2:0x0 80 D:192.168.1.254(3292)
Socket#3:0x0 80 D:192.168.1.254(3290)
Unix time = 1366990004

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x14 80 D:192.168.1.254(3291)
Socket#2:0x0 80 D:192.168.1.254(3292)
Socket#3:0x0 80 D:192.168.1.254(3290)
Unix time = 1366990014

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x14 80 D:192.168.1.254(3291)
Socket#2:0x0 80 D:192.168.1.254(3292)
Socket#3:0x0 80 D:192.168.1.254(3290)
Unix time = 1366990024

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x14 80 D:192.168.1.254(3291)
Socket#2:0x0 80 D:192.168.1.254(3292)
Socket#3:0x0 80 D:192.168.1.254(3290)
Unix time = 1366990034

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x14 80 D:192.168.1.254(3291)
Socket#2:0x0 80 D:192.168.1.254(3292)
Socket#3:0x0 80 D:192.168.1.254(3290)
Unix time = 1366990044
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 26, 2013, 06:53 pm
Dude.  Thanks a ton.  I appreciate immensely what you're doing here.  Unfortunately that's not exactly the same use case.  You only refreshed the browser once.  Notice that in my example after the first time I refreshed I still got responses back from the NTP, but after the second time I refreshed, the NTP stopped. Seems odd, but here's my explanation:

It seems that it's actually related to transition from UDP to a listening socket->connected transition, to being used for UDP again.  When you refresh the first time, you're using socket 0 (which has never been used for UDP) to do the TCP, and the listening port goes to socket 1.  The UDP time server then happens on socket 0 which hasn't been used for UDP *before* TCP.  If you wait about 10 seconds and then refresh, it'll use socket 1 to do the TCP conn, and then listen back on socket 0.  At that point the UDP will take place on socket 1 (which has done the UDP to TCP transition) and it will fail.

Ugh.  this is too complicated a scenario here.  Sorry sorry sorry.  I'm wondering if you can do 1 more test:
1.  Start the code.
2.  wait about 15 seconds.
3.  refresh your browser.
4.  wait about 15 seconds.
5.  refresh your browser again.

Incidentally, I tried to make a simpler scenario by writing some code that connects to itself, but apparently the W5100 won't connect to itself.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 26, 2013, 07:11 pm
Like this?
Quote
Start!
Socket#0:0x22 8888 D:0.0.0.0(0)
Socket#1:0x14 80 D:0.0.0.0(0)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
Client request: GET / HTTP/1.1

POST data:
Sending response
done

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x0 80 D:192.168.1.254(3719)
Socket#2:0x17 80 D:192.168.1.254(3720)
Socket#3:0x14 80 D:0.0.0.0(0)
Unix time = 1366996102
Client request: GET /?t=4&r=3 HTTP/1.1

POST data:
t=4
r=3
Sending response
done

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x0 80 D:192.168.1.254(3719)
Socket#2:0x0 80 D:192.168.1.254(3720)
Socket#3:0x14 80 D:0.0.0.0(0)
Unix time = 1366996112
Client request: GET /?t=5&r=1 HTTP/1.1

POST data:
t=5
r=1
Sending response
done

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x14 80 D:192.168.1.254(3719)
Socket#2:0x0 80 D:192.168.1.254(3720)
Socket#3:0x0 80 D:192.168.1.254(3724)
Unix time = 1366996122
Client request: GET /?t=5&r=1 HTTP/1.1

POST data:
t=5
r=1
Sending response
done

Socket#0:0x22 8888 D:198.55.111.50(123)
Socket#1:0x0 80 D:192.168.1.254(3725)
Socket#2:0x17 80 D:192.168.1.254(3726)
Socket#3:0x14 80 D:192.168.1.254(3724)
Unix time = 1366996132
Client request: GET /favicon.ico HTTP/1.1

POST data:
Sending response
done


edit: Removed my NTP server ip.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 26, 2013, 07:27 pm
I guess I don't understand how your UDP connection got setup on socket 0 and the TCP listening socket is on socket 1?  In the code it calls server.begin() before we've done anything with UDP, so that should use socket 0, and the first showSockStatus() gets called before we've ever done anything with UDP, but your first message shows a UDP socket listening on port 8888 as socket 0.  My first message looks like this:

Quote
Start!
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 0 D:0.0.0.0(0)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)

 
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 26, 2013, 07:32 pm
Here is yours:
Code: [Select]
void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip, INADDR_NONE, gateway, subnet);
delay(500);

Serial.println("Start!");
// here is where the first socket is assigned:
server.begin();
ShowSockStatus();
timer = millis();
}


Here is mine:
Code: [Select]
void setup() {
Serial.begin(9600);

        pinMode(4, OUTPUT);
        digitalWrite(4, HIGH);
       
Ethernet.begin(mac, ip, INADDR_NONE, gateway, subnet);
delay(500);

// here is socket #0
Udp.begin(8888);

Serial.println("Start!");

// here is socket #1
server.begin();
ShowSockStatus();
timer = millis();
}

Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 26, 2013, 07:45 pm
OK.  I see now why yours is working.  You dedicate a socket to the UDP connection that never is freed.  So you never reuse a socket that was previously used as a UDP socket as a TCP socket and vice versa.  Thus you avoid the issue.  In my version the call to CheckTime will create the UDP socket and then tear it down, freeing the  socket for use by other clients. 

What you've got is a workaround for the problem I'm having, but the problem I'm having is still a bug.  The W5100 only has 4 sockets available, and dedicating one of them full time to an NTP client when you only need to use that socket once every few days, and you only need it for about 500ms can be wasteful.  Creating the UDP socket and tearing it down should be a reasonable scenario, but it doesn't work.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 26, 2013, 07:51 pm
You have 4 sockets. Use them wisely. I like the full time UDP socket, and would like to reserve a socket for client stuff when a server is running. Here is my opinion:
http://arduino.cc/forum/index.php/topic,159138.msg1210212.html#msg1210212
Note my sketch uses all the sockets. One (socket#0) for UDP, and the rest (#1-3) for the server.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 26, 2013, 08:10 pm
It sounds like this guy is having exactly the same problem as I am, but he doesn't know it.  He thinks he's running out of sockets, but in actuality the issue is a bug somewhere that won't allow you to reuse a socket that was previously allocated as a TCP socket as a UDP socket.

Your workaround is find for many scenarios, but not mine.  I'm trying to build a simple web server.  One that syncs time via UDP periodically and also includes a TFTP server so you can upload content to the SD card.  TFTP uses 1 UDP socket for the server, and one for the client if it connects.  So, to avoid the bug that I've identified here, I'd have to dedicate one socket to the NTP client, one socket to the TFTP server, one socket to the TFTP client, and then I'd have one remaining socket to use as a my listening socket for HTTP.  Of course that means I don't have a socket to use if someone actually connected to my HTTP server.

In other words, I'm sunk unless I can figure out how to resolve this bug. (or upgrade to the 5200, which seems like a waste)

Incidentally, another workaround is to actually reinitialize the W5100 after every TCP client disconnects.  (i.e. call Ethernet.begin() again)  Of course that means you will also have to go reattach your HTTP server and UDP servers.  Super kludgy, but it may be the only way around this bug.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 26, 2013, 08:25 pm
That one UDP socket will work for every UDP function, like dhcp, ntp, dns, etc...all use that socket. One socket, all that stuff is covered. :)

I know when I am having a problem, but this isn't it. If this was an Apache server, I would expect more.

I will give you the benefit of the doubt, and try to begin and stop a UDP socket and see how it affects the server and the UDP sockets. I'm not sure why I would do that, and I don't really expect it to work. You are assuming that you will need all the sockets for the server simultaneously at times, which would guarantee a NTP fail in that time.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 26, 2013, 08:40 pm
You actually bring up a fantastic point with your DNS example.   When you call EthernetClient::connect(char * host, uint8_t port), it does exactly what I do with NTP.  It dynamically creates a UDP socket for DNS, connects to a server, and then releases that socket.  That should work just fine, except that this bug exists.  I'm certain that I can create a scenario with a http server that has a few connects() in it that will start failing on DNS resolution because of the bug.  There would be no solution either, because you can't manually specify a socket for the DNS server to use.  It just dynamically allocates one from the unused pool.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 26, 2013, 08:49 pm
Sometimes I amaze myself!  8)

Remove the Udp.begin(8888) from setup, and use this checkTime function. How does it do? Works ok here.
Code: [Select]
void checkTime()
{
if(!Udp.begin(8888)) {
          Serial.println("UDP fail");
          return;
        }

  sendNTPpacket(Udp, timeServer); // send an NTP packet to a time server
Serial.println("");
ShowSockStatus();
// wait to see if a reply is available
delay(1000); 
if ( Udp.parsePacket() ) { 
// We've received a packet, read the data from it
Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); 
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord; 

// now convert NTP time into everyday time:
Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;     
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears; 
// print Unix time:
Serial.println(epoch); 

else
Serial.println("UDP FAIL!");
Udp.stop();

}
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 26, 2013, 09:05 pm
Here's a much simpler example using the built in DNS library:

Code: [Select]
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <utility/w5100.h>
#include "Dns.h"

void ShowSockStatus()
{
for (int i = 0; i < MAX_SOCK_NUM; i++) {
Serial.print("Socket#");
Serial.print(i);
uint8_t s = W5100.readSnSR(i);
Serial.print(":0x");
Serial.print(s,16);
Serial.print(" ");
Serial.print(W5100.readSnPORT(i));
Serial.print(" D:");
uint8_t dip[4];
W5100.readSnDIPR(i, dip);
for (int j=0; j<4; j++) {
Serial.print(dip[j],10);
if (j<3) Serial.print(".");
}
Serial.print("(");
Serial.print(W5100.readSnDPORT(i));
Serial.println(")");
}
}

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

EthernetServer server(80);
IPAddress dnsserver(192,168,10,1);
IPAddress ip(192,168,10,20);
IPAddress gateway(192,168,10, 2);
IPAddress subnet(255, 255, 255, 0);

long timer;

void setup() {
Serial.begin(9600);
Ethernet.begin(mac, ip, dnsserver, gateway, subnet);
delay(500);

Serial.println("Start!");
server.begin();
ShowSockStatus();
timer = millis();
}

void loop()
{
//Check if a web client has attached.
EthernetClient client = server.available();
if (client) {
Serial.println("new Client");
ShowSockStatus();
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.print(c);
if (c == '\n' && currentLineIsBlank) {
client.stop();
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}

if ((millis() - timer) > 5000) {
DNSClient dns;
IPAddress remote_addr;
dns.begin(dnsserver);
if (dns.getHostByName("www.yahoo.com", remote_addr) == 1)
{
for (int i=0; i<4; i++) {
Serial.print(remote_addr[i]);
if (i!=3)
Serial.print('.');
else
Serial.println("");
}
}
else
Serial.println("DNS FAIL!");
timer = millis();
ShowSockStatus();
}
}


And the output

Code: [Select]
Start!
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 0 D:0.0.0.0(0)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
98.139.183.24
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 1030 D:192.168.10.1(53)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
98.138.253.109
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 1024 D:192.168.10.1(53)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
98.138.253.109
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 1024 D:192.168.10.1(53)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x17 80 D:192.168.10.213(11298)
Socket#1:0x17 80 D:192.168.10.213(11299)
Socket#2:0x14 80 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.10.20
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
98.139.183.24
Socket#0:0x0 1035 D:192.168.10.1(53)
Socket#1:0x17 80 D:192.168.10.213(11299)
Socket#2:0x14 80 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
98.138.253.109
Socket#0:0x0 1029 D:192.168.10.1(53)
Socket#1:0x17 80 D:192.168.10.213(11299)
Socket#2:0x14 80 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
98.139.183.24
Socket#0:0x0 1039 D:192.168.10.1(53)
Socket#1:0x0 80 D:192.168.10.213(11299)
Socket#2:0x14 80 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x17 80 D:192.168.10.213(11312)
Socket#1:0x14 80 D:192.168.10.213(11299)
Socket#2:0x17 80 D:192.168.10.213(11311)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.10.20
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
98.138.253.109
Socket#0:0x17 80 D:192.168.10.213(11312)
Socket#1:0x14 80 D:192.168.10.213(11299)
Socket#2:0x0 1033 D:192.168.10.1(53)
Socket#3:0x0 0 D:0.0.0.0(0)
98.139.183.24
Socket#0:0x17 80 D:192.168.10.213(11312)
Socket#1:0x14 80 D:192.168.10.213(11299)
Socket#2:0x0 1028 D:192.168.10.1(53)
Socket#3:0x0 0 D:0.0.0.0(0)
98.138.253.109
Socket#0:0x17 80 D:192.168.10.213(11312)
Socket#1:0x14 80 D:192.168.10.213(11299)
Socket#2:0x0 1039 D:192.168.10.1(53)
Socket#3:0x0 0 D:0.0.0.0(0)
DNS FAIL!
Socket#0:0x0 1034 D:192.168.10.1(53)
Socket#1:0x14 80 D:192.168.10.213(11299)
Socket#2:0x0 1039 D:192.168.10.1(53)
Socket#3:0x0 0 D:0.0.0.0(0)
DNS FAIL!
Socket#0:0x0 1033 D:192.168.10.1(53)
Socket#1:0x14 80 D:192.168.10.213(11299)
Socket#2:0x0 1039 D:192.168.10.1(53)
Socket#3:0x0 0 D:0.0.0.0(0)



Notice how it works right up till it tries to reuse socket #0 to do the DNS (which has previously been used as UDP/DNS and then TCP).  Then it fails...
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 26, 2013, 11:15 pm
If I use a reliable dns server, I cannot replicate your error with my code. Both NTP and DNS work. Is 192.168.10.1 a good dns server? My NTP and DNS changes sockets (they both use the same socket) and has no problem. ??
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 27, 2013, 01:00 am
Are you using the code I put in the message?  There shouldn't be any NTP packets going across because there's nothing NTP related in that code. 

It's a reliable DNS server.  If I never browse to the web port on the Arduino then it'll sit there and poll forever with no issues.  In fact it's been up polling for the past 3 hours and has not had a single failure.  As soon as I browse to we web port though, it fails (well, I actually have to browse twice for it to happen).
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 27, 2013, 12:25 pm
Quote
Are you using the code I put in the message?

I am testing the code from your reply #16 now. I changed the network settings and dns server to mine, and have it resolving my local domain name instead of yahoo. It has not failed yet, despite the requests to the server and the "No data received" message.

When resolving yahoo, I got errors if I try to resolve the name too often, no matter if I loaded the webpage or not.

edit: This is after I removed my SD card from the shield slot. NTP, dhcp and dns have a problem if there is a card in the slot and not disabled or initialized correctly.

It has been running about an hour with several dozen requests to the server, and not one fail of either service.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 28, 2013, 06:09 pm
Thanks Tim.  I should have mentioned the SD card thing.  I didn't include any initialization code to turn of the SD card.

I guess I'd love to see your output if you have it available...

I'm beginning to think that your setup is just not exhibiting the same things that mine is.  Maybe there's a batch of 5100s that have bugs?  Maybe it's my version of the Ethernet shield.  (I've got a couple that I bought off eBay).  I don't know.  I've used two different shields with three different boards (2 megas and 1 Uno).  I've got no idea why it seems so repeatable on my setup with very varied scenarios, but we can't seem to get yours to exhibit the same thing.

Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 28, 2013, 06:38 pm
Give me a bit to setup the test again. I am testing the ethernet shield's dhcp client function. I think my router has a bug in the dhcp server service. I will replace my public ip with a phoney. I don't need any DoS attacks. I get enough, thanks.

Check back in a bit... :)
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 28, 2013, 06:41 pm
Does seem odd that it would fail for a DNS request that only came once every 5 seconds.  That's pretty far from a DoS.  Anyway, I changed my code to use 4.2.2.1 public DNS.  I posted it on the other thread...
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 28, 2013, 06:47 pm
I am concerned about DoS when publishing my public ip, and not because of this code. Here is my serial monitor display for a short run. It will go on for hours like this.
Quote
Start!
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 0 D:0.0.0.0(0)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
xx.xx.58.116
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 1024 D:xx.xx.58.115(53)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
xx.xx.58.116
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 1036 D:xx.xx.58.115(53)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
xx.xx.58.116
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 1031 D:xx.xx.58.115(53)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x17 80 D:192.168.1.254(3691)
Socket#1:0x17 80 D:192.168.1.254(3692)
Socket#2:0x14 80 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.2.2
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
xx.xx.58.116
Socket#0:0x0 1026 D:xx.xx.58.115(53)
Socket#1:0x17 80 D:192.168.1.254(3692)
Socket#2:0x14 80 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x17 80 D:192.168.1.254(3692)
Socket#2:0x17 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.2.2
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
xx.xx.58.116
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x0 1038 D:xx.xx.58.115(53)
Socket#2:0x17 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
xx.xx.58.116
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x0 1034 D:xx.xx.58.115(53)
Socket#2:0x0 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x17 80 D:192.168.1.254(3694)
Socket#1:0x17 80 D:192.168.1.254(3695)
Socket#2:0x14 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.2.2
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
xx.xx.58.116
Socket#0:0x0 1029 D:xx.xx.58.115(53)
Socket#1:0x17 80 D:192.168.1.254(3695)
Socket#2:0x14 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x17 80 D:192.168.1.254(3695)
Socket#2:0x17 80 D:192.168.1.254(3698)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.2.2
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
xx.xx.58.116
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x0 1024 D:xx.xx.58.115(53)
Socket#2:0x17 80 D:192.168.1.254(3698)
Socket#3:0x0 0 D:0.0.0.0(0)
a
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
xx.xx.58.116
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 1024 D:xx.xx.58.115(53)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
xx.xx.58.116
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 1036 D:xx.xx.58.115(53)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
xx.xx.58.116
Socket#0:0x14 80 D:0.0.0.0(0)
Socket#1:0x0 1031 D:xx.xx.58.115(53)
Socket#2:0x0 0 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x17 80 D:192.168.1.254(3691)
Socket#1:0x17 80 D:192.168.1.254(3692)
Socket#2:0x14 80 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.2.2
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
xx.xx.58.116
Socket#0:0x0 1026 D:xx.xx.58.115(53)
Socket#1:0x17 80 D:192.168.1.254(3692)
Socket#2:0x14 80 D:0.0.0.0(0)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x17 80 D:192.168.1.254(3692)
Socket#2:0x17 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.2.2
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
xx.xx.58.116
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x0 1038 D:xx.xx.58.115(53)
Socket#2:0x17 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
xx.xx.58.116
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x0 1034 D:xx.xx.58.115(53)
Socket#2:0x0 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x17 80 D:192.168.1.254(3694)
Socket#1:0x17 80 D:192.168.1.254(3695)
Socket#2:0x14 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.2.2
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
xx.xx.58.116
Socket#0:0x0 1029 D:xx.xx.58.115(53)
Socket#1:0x17 80 D:192.168.1.254(3695)
Socket#2:0x14 80 D:192.168.1.254(3693)
Socket#3:0x0 0 D:0.0.0.0(0)
new Client
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x17 80 D:192.168.1.254(3695)
Socket#2:0x17 80 D:192.168.1.254(3698)
Socket#3:0x0 0 D:0.0.0.0(0)
GET / HTTP/1.1
Host: 192.168.2.2
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

client disconnected
xx.xx.58.116
Socket#0:0x14 80 D:xx.xx.58.115(53)
Socket#1:0x0 1024 D:xx.xx.58.115(53)
Socket#2:0x17 80 D:192.168.1.254(3698)
Socket#3:0x0 0 D:0.0.0.0(0)

Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: sonnyyu on Apr 28, 2013, 06:55 pm
my 2 cents;-

UDP is a lightweight protocol that by design doesn't handle things like packet sequencing. It does not guarantee that your packets will arrive in order (It does not even guarantee that your packets will arrive at all.) .
Say send command  set voltage=1 v, then set voltage=4 v, You might get 0v or 1v or 4v if default is 0v. TCP is a better choice if you want robust packet delivery and sequencing.
If you're limited to using UDP you would have to develop a method of identifying the out of sequence packets and resequencing them or request to resend, but for Arduino is tough task.

a lot people implement UDP with Arduino, I mean neither OP nor this thread please hold fire.

I guess either they drink too much Italian coffee or I drink too much, might be both.  :P
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 28, 2013, 07:01 pm
@sonnyyu: That is a good thought, but NTP, DNS, and DHCP use UDP. You really can't avoid it.

Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: sonnyyu on Apr 28, 2013, 07:03 pm

@sonnyyu: That is a good thought, but NTP, DNS, and DHCP use UDP. You really can't avoid it.




I mean neither OP nor this thread please hold fire.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 28, 2013, 07:05 pm
I'm not firing at you.  :)  I'm just stating a fact. I am not fond of UDP either as a reliable transfer, but we are subjected to it through theses services.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 28, 2013, 07:05 pm
Thanks,  that's 100% definitive.  You are not having the same issue as I am, although I have no idea why...

One thing I just found out was that if the TCP request comes from the same machine as the UDP destination goes to (i.e. if you run a WGET from the same router that's hosting your DNS server) the problem never happens (for me).  It's almost like it's a IP->MAC arp issue.  Odd.  I'm going to delve into this a bit more before I bother anyone.  Looking up W5100 and ARP I did come up with this:  http://forums.parallax.com/showthread.php/129515-W5100-Sn_SR-undocumented-misfeature-bug  Not sure if that's related though...  I'll get to the bottom of this at some point...

Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 28, 2013, 07:12 pm
Maybe you are right. Maybe the delay waiting for the response from the dns server is not long enough. That could cause the dns fail.

edit: Your test is still running on my Arduino. It has not missed a beat since I started it.
Just so you know...
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Apr 28, 2013, 07:27 pm
Wow,  OK.  Still not to the bottom of this, but I just had a pretty big discovery.  When I get the DNS failure, the packet actually goes to the wrong machine!  In my example I posted the DNS server was outside my network, so it should have been sent to the gateway MAC address.  However, with a packet capture I found that it actually ended up going to the same machine that my TCP request came from!!!

That's exactly why this isn't working right.  For some reason the W5100 gets confused and doesn't update the IP->MAC port for that socket.  I'm going to delve into this a bit more to see if I can get to the bottom of what's going on...
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: sonnyyu on Apr 28, 2013, 07:35 pm
Some background information about  NTP, DNS, and DHCP use UDP;-

DNS  works on both TCP and UDP

DHCP works on UDP only

Its use is in a typical local area network (LAN). The packet sequencing is never problem.

NTP

It used work both TCP and UDP [RFC0793] , UDP/TCP Port 123 was previously assigned by IANA for NTP. The new [RFC5905] drop TCP support. Here is the reason;- "Reliable message delivery such as TCP [RFC0793] can actually make the delivered NTP packet less reliable since retries would increase the delay value and other errors."  obviously implement correctly UDP client is needed to take care the issue.

Now the question is "What Arduino NTP client does ?"




Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 28, 2013, 07:42 pm
That could be it. I just tried the same test using a remote dns server and my domain, and it crashed like the Hindenberg.  :(

Now I am back to a localnet dns server and it is ok.

@sonnyyu: No question there. Arduino NTP uses UDP.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: sonnyyu on Apr 28, 2013, 07:48 pm

That could be it. I just tried the same test using a remote dns server and my domain, and it crashed like the Hindenberg.  :(

Now I am back to a localnet dns server and it is ok.

@sonnyyu: No question there. Arduino NTP uses UDP.



My fault, the complete question is;

What Arduino NTP client does to take care reliable NTP packet deliver?

This might hijack the thread, I might start new thread about it.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Apr 28, 2013, 07:52 pm
It does nothing for "reliable". It waits 1 second. If no response, it bails.

And the remote server thing just went out the window. I forgot to remove my SD card again, and you code does not disable it. It is working fine with my domain and a remote dns server.
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: tomtek on Nov 21, 2013, 07:56 pm
I have also hit this bug along with this thread in searching for an answer.

I can add a couple of things I have found trying to fix this.

It appears to be any protocol TCP then UDP or TCP then ICMP are the 2 bugs I have encountered.  If the Wiznet socket is used for TCP it can't do ICMP reliably either to a different IP then TCP was connected with.  I haven't proven it out for 100% sure but I do believe this bug is true for UDP first then ICMP on the same socket.

I have also had it ping the wrong IP (always the GW IP) I believe this is a known bug that is in the latest Wiznet errata stating that you need to leave the GW and mask set to zeros until you open connections this prevents the ARP request returning the GW MAC as a default.

Multiple other bugs in the Arduino Ethernet library.  DNS returning positive results with the wrong IP if the lookup failed.  Ethernet client connections that only work through a GW but not on the same subnet.

Arduino Due is  @ 192.168.20.151 with a valid unique MAC Address

socket 0 -> TCP with 192.168.20.2 ->close TCP -> ICMP Ping to 192.168.20.254(works once then fails)
socket  1 -> TCP with 192.168.20.2 - >open,close,open close TCP always works
socket 2 - > TCP with 192.168.20.2 always works
socket 3 -> ICMP Ping to 192.168.20.254 always works never has TCP on it.

Here is something additional that leans towards an ARP table problem.

socket 0 -> TCP with 192.168.20.2 ->close TCP -> ICMP Ping to 192.168.20.2(Works fine)
socket  1 -> TCP with 192.168.20.2 - >open,close,open close TCP always works
socket 2 - > TCP with 192.168.20.2 always works
socket 3 -> ICMP Ping to 192.168.20.254 always works never has TCP on it.

Its like all 4 sockets share the same ARP table that is too short to stay updated for multiple connections on multiple sockets.

If TCP and ICMP are trying to talk to the same IP and of course MAC address all works no failures.

I tried watching the states that show the MAC address has been resolved.

I think a TCP/IP stack that just uses the MAC Raw mode is the only true solution.  I need TCP/UDP/ICMP/Multicast UDP to function at any given time on any given open Wiznet socket.

Tom
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: zimm0who0net on Nov 21, 2013, 08:06 pm
Tom,  I never did get a solution to this W5100 bug.  I ended up implementing a workaround that just kept re-trying on failures.  I agree 100% that this is an ARP issue that seems to manifest itself when you switch from TCP to UDP on the same socket.

Wish I could be of more help. 
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: the_sensor on Jan 07, 2014, 09:19 pm
So it looks like the Wiznet errata (http://www.wiznet.co.kr/Admin_Root/UpLoad_Files/BoardFiles/3150Aplus_5100_errata_en_v2.4.pdf) does show a fix for this problem. However if I look in the Arduino libraries which I'm using (Arduino 1.0.5) I'm not able to find the implementation of this fix. Has anyone ever tried to implement this fix ? At first sight it shouldn't be it too difficult as it involves just a few fixes in libraries/Ethernet/utility/socket.cpp.

FYI: I ended up on this thread as I'm having problems with UDP and TCP connections, but I'm not yet sure if the problem in this thread is the same as my problem. I have not debugged it that far yet...
Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: Apollon77 on Sep 06, 2015, 11:04 pm
Hey all,

I know the last post here is way over a year ago, but I had comparable problems with the most current Arduino IDE 1.6.5 and I wanted to know if anyone found a solution ?! Or was there fixes done in Ethernet Library or does someone has done it by it's own?

I have added an NTP query to my code and Ethernet became unstable and/r blocked sockets appeared. The NTP query was using UDP as already mentioned here ...

For now I created a TCP-UDP-Tunnel using socat in my local network and changed the NTP code to use TCP and anything is stable again ... yes  know that TCP is not the best and a TCP-UDP-tunnel also needs time but I don't need the time microsecond-exact ;-)

Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: SurferTim on Sep 07, 2015, 05:25 am
I haven't experienced a problem using UDP and TCP. What do you mean by this?
Quote
I have added an NTP query to my code and Ethernet became unstable and/r blocked sockets appeared. The NTP query was using UDP as already mentioned here ...
How did you determine the blocked sockets? How did it become unstable?

Title: Re: W5100/Ethernet cannot use socket as UDP after using it as TCP
Post by: vadimsachkov on Sep 15, 2017, 04:10 pm
I think I found the problem sending UDP packets after TCP in the same socket. The problem, as stated above in this forum , is that if you are sending the UDP packet fails in the ARP request and in the register SnDHAR remains the MAC address of the previous request. To remedy the situation, do the following :
1. open the socket : Udp.start (port)
2. record to the register SnDIPR broadcast address :
uint8_t ip[6]={0xff,0xff,0xff,0xff}; W5100.writeSnDIPR(sock, ip);
3. use the command send dummy packet Udp.endPacket();
4. Next is usually to prepare a pack for recording : Udp.startPacket(server, serverport)
5. to record the desired Udp.write(data,len)
6. sent packet: Udp.endPacket();
7. close the Udp socket.stop();

PS. to find out the socket for paragraph 2. you can , for example, to change the EthernetUDP class , adding to the function uint8_t getsocket (){return _sock;},
or you can create a inherited class EthernetUDPMy: public EthernetUDP, and where to add the function getsocket().





Code: [Select]

class  EthernetUDPMy : public EthernetUDP {
public:
EthernetUDPMy::EthernetUDPMy() : EthernetUDP () {};
uint8_t getsocket() {return _sock;}

};
EthernetUDPMy Udp;



//.......

if (Udp.getsocket()==MAX_SOCK_NUM) {
Serial.println("Udp Open Socket");
if (!Udp.begin(localUdpPort)) return 0;
clearArpUdp(Udp.getsocket());
Udp.endPacket();
}
if (!Udp.beginPacket(serverstr, port)) {Udp.stop(); return 0;}
//....
rez=Udp.write(data, len);
int isSent=Udp.endPacket();
if (rez!=len || !isSent) {
Serial.println("Error sent UDP");
Udp.stop();
rez=0;
}





void clearArpUdp(SOCKET sock){
if (sock>=MAX_SOCK_NUM) return;
SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
uint8_t c[6]={0xff,0xff,0xff,0xff};
W5100.writeSnDIPR(sock, c);
SPI.endTransaction();
}