| Line No. | Rev | Author | Line |
|---|---|---|---|
| 1 | 32 | kaklik | /********************************************************************* |
| 2 | * |
||
| 3 | * Dynamic DNS Client Module |
||
| 4 | * Reference: DNS Update API Version 2.0.3 (www.dyndns.com) |
||
| 5 | * |
||
| 6 | ********************************************************************* |
||
| 7 | * FileName: DynDNS.c |
||
| 8 | * Dependencies: TCP, Tick |
||
| 9 | * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32 |
||
| 10 | * Compiler: Microchip C32 v1.05 or higher |
||
| 11 | * Microchip C30 v3.12 or higher |
||
| 12 | * Microchip C18 v3.30 or higher |
||
| 13 | * HI-TECH PICC-18 PRO 9.63PL2 or higher |
||
| 14 | * Company: Microchip Technology, Inc. |
||
| 15 | * |
||
| 16 | * Software License Agreement |
||
| 17 | * |
||
| 18 | * Copyright (C) 2002-2009 Microchip Technology Inc. All rights |
||
| 19 | * reserved. |
||
| 20 | * |
||
| 21 | * Microchip licenses to you the right to use, modify, copy, and |
||
| 22 | * distribute: |
||
| 23 | * (i) the Software when embedded on a Microchip microcontroller or |
||
| 24 | * digital signal controller product ("Device") which is |
||
| 25 | * integrated into Licensee's product; or |
||
| 26 | * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h, |
||
| 27 | * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device |
||
| 28 | * used in conjunction with a Microchip ethernet controller for |
||
| 29 | * the sole purpose of interfacing with the ethernet controller. |
||
| 30 | * |
||
| 31 | * You should refer to the license agreement accompanying this |
||
| 32 | * Software for additional information regarding your rights and |
||
| 33 | * obligations. |
||
| 34 | * |
||
| 35 | * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT |
||
| 36 | * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT |
||
| 37 | * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A |
||
| 38 | * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
||
| 39 | * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR |
||
| 40 | * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF |
||
| 41 | * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS |
||
| 42 | * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE |
||
| 43 | * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER |
||
| 44 | * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT |
||
| 45 | * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE. |
||
| 46 | * |
||
| 47 | * |
||
| 48 | * Author Date Comment |
||
| 49 | *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
| 50 | * Amit Shirbhate 3/24/08 Original |
||
| 51 | ********************************************************************/ |
||
| 52 | #ifndef __DYNDNSCLIENT_C |
||
| 53 | #define __DYNDNSCLIENT_C |
||
| 54 | |||
| 55 | #include "TCPIPConfig.h" |
||
| 56 | |||
| 57 | #if defined STACK_USE_DYNAMICDNS_CLIENT |
||
| 58 | |||
| 59 | #include "TCPIP Stack/TCPIP.h" |
||
| 60 | |||
| 61 | // Delimiter to locate IP address from CheckIP server |
||
| 62 | static ROM BYTE _checkIpSrvrResponse[] = "Address:"; |
||
| 63 | |||
| 64 | // Response codes from DynDNS Update Server |
||
| 65 | static ROM char* _updateIpSrvrResponse[] = |
||
| 66 | { |
||
| 67 | /* 0 */ "good", // Update was successful |
||
| 68 | /* 1 */ "nochg", // No change was made; request is considered abusive |
||
| 69 | /* 2 */ "abuse", // Account has been blocked for abuse |
||
| 70 | /* 3 */ "badsys", // System is not supported |
||
| 71 | /* 4 */ "badagent", // Agent has been blocked for abuse |
||
| 72 | /* 5 */ "badauth", // Authentication failed |
||
| 73 | /* 6 */ "!donator", // A paid account feature was requested on a free account |
||
| 74 | /* 7 */ "notfqdn", // Hostname was not a fully-qualified domain name |
||
| 75 | /* 8 */ "nohost", // Host name was not found in the system |
||
| 76 | /* 9 */ "!yours", // The specified hostname does not belong to this account |
||
| 77 | /* 10 */ "numhost", // Number of hosts does not match / serious error |
||
| 78 | /* 11 */ "dnserr", // System error was encountered, try again soon |
||
| 79 | /* 12 */ "911", // System error was encountered, try again later |
||
| 80 | }; |
||
| 81 | |||
| 82 | /**************************************************************************** |
||
| 83 | Section: |
||
| 84 | Dynamic DNS Services |
||
| 85 | These services must support the DynDNS API, and correspond to |
||
| 86 | DDNS_SERVICES enumeration |
||
| 87 | ***************************************************************************/ |
||
| 88 | |||
| 89 | // Host names for various Dynamic DNS services |
||
| 90 | ROM char * ROM ddnsServiceHosts[] = |
||
| 91 | { |
||
| 92 | "members.dyndns.org", // DYNDNS_ORG |
||
| 93 | "dynupdate.no-ip.com", // NO_IP_COM |
||
| 94 | "updates.dnsomatic.com", // DNSOMATIC_COM |
||
| 95 | }; |
||
| 96 | |||
| 97 | // Port numbers for various Dynamic DNS services |
||
| 98 | static ROM WORD ddnsServicePorts[] = |
||
| 99 | { |
||
| 100 | 80, // DYNDNS_ORG |
||
| 101 | 80, // NO_IP_COM |
||
| 102 | 80, // DNSOMATIC_COM |
||
| 103 | }; |
||
| 104 | |||
| 105 | /**************************************************************************** |
||
| 106 | Section: |
||
| 107 | Global Variables |
||
| 108 | ***************************************************************************/ |
||
| 109 | static IP_ADDR lastKnownIP; // Last known IP address of this device |
||
| 110 | static DDNS_STATUS lastStatus; // Status response from last update |
||
| 111 | |||
| 112 | DDNS_POINTERS DDNSClient; // Configuration parameters for the module |
||
| 113 | |||
| 114 | static DWORD dwUpdateAt; // Indicates when the next CheckIP should be done |
||
| 115 | static BOOL bForceUpdate; // Indicates that the update should be done regardless |
||
| 116 | // of whether or not the IP changed. Use this flag |
||
| 117 | // when the user/pass/hostname have changed. |
||
| 118 | |||
| 119 | /**************************************************************************** |
||
| 120 | Function: |
||
| 121 | void DDNSInit(void) |
||
| 122 | |||
| 123 | Summary: |
||
| 124 | Initializes the Dynamic DNS module. |
||
| 125 | |||
| 126 | Description: |
||
| 127 | This function initializes the Dynamic DNS client. It clears the |
||
| 128 | DDNSClient pointers structure, and tells the module to attempt the |
||
| 129 | first update after 15 seconds have elapsed (so as to allow the DHCP |
||
| 130 | configuration to stabalize). |
||
| 131 | |||
| 132 | Precondition: |
||
| 133 | None |
||
| 134 | |||
| 135 | Parameters: |
||
| 136 | None |
||
| 137 | |||
| 138 | Returns: |
||
| 139 | None |
||
| 140 | |||
| 141 | Remarks: |
||
| 142 | This function is called only one during lifetime of the application. |
||
| 143 | ***************************************************************************/ |
||
| 144 | void DDNSInit(void) |
||
| 145 | { |
||
| 146 | // Clear the Dynamic DNS Client to start |
||
| 147 | memset((void*)&DDNSClient, 0x00, sizeof(DDNSClient)); |
||
| 148 | |||
| 149 | // Use the default Check IP server |
||
| 150 | DDNSClient.ROMPointers.CheckIPServer = 1; |
||
| 151 | DDNSClient.CheckIPServer.szROM = DDNS_CHECKIP_SERVER; |
||
| 152 | DDNSClient.CheckIPPort = DDNS_DEFAULT_PORT; |
||
| 153 | |||
| 154 | // First update is 15 seconds after boot, allowing DHCP to stabilize |
||
| 155 | dwUpdateAt = TickGet() + 15*TICK_SECOND; |
||
| 156 | bForceUpdate = TRUE; |
||
| 157 | lastStatus = DDNS_STATUS_UNKNOWN; |
||
| 158 | } |
||
| 159 | |||
| 160 | /**************************************************************************** |
||
| 161 | Function: |
||
| 162 | void DDNSTask(void) |
||
| 163 | |||
| 164 | Summary: |
||
| 165 | Dynamic DNS client task/state machine. |
||
| 166 | |||
| 167 | Description: |
||
| 168 | This function performs the background tasks of the Dynamic DNS Client. |
||
| 169 | Once the DDNSPointers structure is configured, this task attempt to |
||
| 170 | update the Dynamic DNS hostname on a periodic schedule. |
||
| 171 | |||
| 172 | The task first accesses the CheckIP server to determine the device's |
||
| 173 | current external IP address. If the IP address has changed, it |
||
| 174 | issues an update command to the dynamic DNS service to propagate the |
||
| 175 | change. This sequence executes whenever dwUpdateAt elapses, which by |
||
| 176 | default is every 10 minutes, or when an update is forced. |
||
| 177 | |||
| 178 | Precondition: |
||
| 179 | DDNSInit() has been called. |
||
| 180 | |||
| 181 | Parameters: |
||
| 182 | None |
||
| 183 | |||
| 184 | Returns: |
||
| 185 | None |
||
| 186 | |||
| 187 | Remarks: |
||
| 188 | This function acts as a task (similar to one in an RTOS). It |
||
| 189 | performs its task in a co-operative manner, and the main application |
||
| 190 | must call this function periodically to ensure that its tasks get |
||
| 191 | executed in a timely fashion. |
||
| 192 | ***************************************************************************/ |
||
| 193 | void DDNSTask(void) |
||
| 194 | { |
||
| 195 | BYTE i; |
||
| 196 | static DWORD Timer; |
||
| 197 | static TCP_SOCKET MySocket = INVALID_SOCKET; |
||
| 198 | static char ROM * ROMStrPtr; |
||
| 199 | static char * RAMStrPtr; |
||
| 200 | |||
| 201 | static BYTE vBuffer[16]; |
||
| 202 | WORD wPos; |
||
| 203 | static IP_ADDR ipParsed; |
||
| 204 | |||
| 205 | static enum |
||
| 206 | { |
||
| 207 | SM_IDLE = 0u, |
||
| 208 | SM_BEGIN_CHECKIP, //0x1 |
||
| 209 | SM_CHECKIP_SKT_OBTAINED, //0x2 |
||
| 210 | SM_CHECKIP_FIND_DELIMITER, //0x3 |
||
| 211 | SM_CHECKIP_FIND_ADDRESS, //0x4 |
||
| 212 | SM_CHECKIP_DISCONNECT, //0x5 |
||
| 213 | SM_IP_UPDATE_HOME, //0x6 |
||
| 214 | SM_IP_UPDATE_SKT_OBTAINED, //0x7 |
||
| 215 | |||
| 216 | /* |
||
| 217 | HTTP request msg is divided into 6 parts |
||
| 218 | SM_IP_UPDATE_REQ_A,B,C,D,E,F as the tcp ip tx |
||
| 219 | buffer is only able to carry 200 bytes at a time. |
||
| 220 | */ |
||
| 221 | |||
| 222 | SM_IP_UPDATE_REQ_A, //0x8 |
||
| 223 | SM_IP_UPDATE_REQ_B, //0x9 |
||
| 224 | SM_IP_UPDATE_REQ_C, //0xa |
||
| 225 | SM_IP_UPDATE_REQ_D, //0xb |
||
| 226 | SM_IP_UPDATE_REQ_E, //0xc |
||
| 227 | SM_IP_UPDATE_REQ_F, //0xd |
||
| 228 | |||
| 229 | SM_IPUPDATE_FIND_RESPONSE, //0xe |
||
| 230 | SM_IPUPDATE_PARSE_RESPONSE, //0xf |
||
| 231 | SM_IPUDATE_DISCONNECT, //0x10 |
||
| 232 | SM_DONE, // Done, try again in 10 minutes |
||
| 233 | SM_SOFT_ERROR, // Soft error, try again in 30 seconds |
||
| 234 | SM_SYSTEM_ERROR // System error, try again in 30 minutes |
||
| 235 | } smDDNS = SM_IDLE; |
||
| 236 | |||
| 237 | switch(smDDNS) |
||
| 238 | { |
||
| 239 | case SM_IDLE: |
||
| 240 | |||
| 241 | // Wait for timeout to begin IP check |
||
| 242 | if((LONG)(TickGet() - dwUpdateAt) < 0) |
||
| 243 | break; |
||
| 244 | |||
| 245 | // Otherwise, continue to next state |
||
| 246 | smDDNS = SM_BEGIN_CHECKIP; |
||
| 247 | |||
| 248 | case SM_BEGIN_CHECKIP: |
||
| 249 | |||
| 250 | // If a fatal error has occurred, abort to the SM_DONE state and keep |
||
| 251 | // the error message. |
||
| 252 | if(lastStatus >= DDNS_STATUS_ABUSE && lastStatus <= DDNS_STATUS_911) |
||
| 253 | { |
||
| 254 | smDDNS = SM_DONE; |
||
| 255 | break; |
||
| 256 | } |
||
| 257 | |||
| 258 | // If DDNSClient is not properly configured, abort |
||
| 259 | if( |
||
| 260 | // Verify that each pointer is not null, and is not empty |
||
| 261 | (DDNSClient.ROMPointers.Host && (!DDNSClient.Host.szROM || *DDNSClient.Host.szROM == '\0') ) || |
||
| 262 | (!DDNSClient.ROMPointers.Host && (!DDNSClient.Host.szRAM || *DDNSClient.Host.szRAM == '\0') ) || |
||
| 263 | (DDNSClient.ROMPointers.Username && (!DDNSClient.Username.szROM || *DDNSClient.Username.szROM == '\0') ) || |
||
| 264 | (!DDNSClient.ROMPointers.Username && (!DDNSClient.Username.szRAM || *DDNSClient.Username.szRAM == '\0') ) || |
||
| 265 | (DDNSClient.ROMPointers.Password && (!DDNSClient.Password.szROM || *DDNSClient.Password.szROM == '\0') ) || |
||
| 266 | (!DDNSClient.ROMPointers.Password && (!DDNSClient.Password.szRAM || *DDNSClient.Password.szRAM == '\0') ) || |
||
| 267 | (DDNSClient.ROMPointers.CheckIPServer && (!DDNSClient.CheckIPServer.szROM || *DDNSClient.CheckIPServer.szROM == '\0') ) || |
||
| 268 | (!DDNSClient.ROMPointers.CheckIPServer && (!DDNSClient.CheckIPServer.szRAM || *DDNSClient.CheckIPServer.szRAM == '\0') ) || |
||
| 269 | (DDNSClient.ROMPointers.UpdateServer && (!DDNSClient.UpdateServer.szROM || *DDNSClient.UpdateServer.szROM == '\0') ) || |
||
| 270 | (!DDNSClient.ROMPointers.UpdateServer && (!DDNSClient.UpdateServer.szRAM || *DDNSClient.UpdateServer.szRAM == '\0') ) |
||
| 271 | ) |
||
| 272 | { |
||
| 273 | smDDNS = SM_SOFT_ERROR; |
||
| 274 | lastStatus = DDNS_STATUS_INVALID; |
||
| 275 | break; |
||
| 276 | } |
||
| 277 | |||
| 278 | // Start with an invalidated IP String |
||
| 279 | vBuffer[0] = '\0'; |
||
| 280 | |||
| 281 | // Connect a socket to the remote server |
||
| 282 | if(DDNSClient.ROMPointers.CheckIPServer) |
||
| 283 | { |
||
| 284 | MySocket = TCPOpen((DWORD)(ROM_PTR_BASE)DDNSClient.CheckIPServer.szROM, TCP_OPEN_ROM_HOST, |
||
| 285 | DDNSClient.CheckIPPort, TCP_PURPOSE_DEFAULT); |
||
| 286 | } |
||
| 287 | else |
||
| 288 | { |
||
| 289 | MySocket = TCPOpen((DWORD)(PTR_BASE)DDNSClient.CheckIPServer.szRAM, TCP_OPEN_RAM_HOST, |
||
| 290 | DDNSClient.CheckIPPort, TCP_PURPOSE_DEFAULT); |
||
| 291 | } |
||
| 292 | |||
| 293 | // If no socket available, try again on next loop |
||
| 294 | if(MySocket == INVALID_SOCKET) |
||
| 295 | break; |
||
| 296 | |||
| 297 | smDDNS++; |
||
| 298 | Timer = TickGet(); |
||
| 299 | break; |
||
| 300 | |||
| 301 | case SM_CHECKIP_SKT_OBTAINED: |
||
| 302 | |||
| 303 | // Wait for the remote server to accept our connection request |
||
| 304 | if(!TCPIsConnected(MySocket)) |
||
| 305 | { |
||
| 306 | // Time out if too much time is spent in this state |
||
| 307 | if(TickGet()-Timer > 6*TICK_SECOND) |
||
| 308 | { |
||
| 309 | // Close the socket so it can be used by other modules |
||
| 310 | // We will retry soon |
||
| 311 | TCPDisconnect(MySocket); |
||
| 312 | MySocket = INVALID_SOCKET; |
||
| 313 | lastStatus = DDNS_STATUS_CHECKIP_ERROR; |
||
| 314 | smDDNS = SM_SOFT_ERROR; |
||
| 315 | } |
||
| 316 | break; |
||
| 317 | } |
||
| 318 | |||
| 319 | Timer = TickGet(); |
||
| 320 | |||
| 321 | // Make certain the socket can be written to |
||
| 322 | if(TCPIsPutReady(MySocket) < 125u)//125 = size of TCP Tx buffer |
||
| 323 | break; |
||
| 324 | |||
| 325 | // Transmit the request to the server |
||
| 326 | TCPPutROMString(MySocket, (ROM BYTE*)"GET / HTTP/1.0\r\nHost: "); |
||
| 327 | |||
| 328 | if(DDNSClient.ROMPointers.CheckIPServer) |
||
| 329 | { |
||
| 330 | TCPPutROMString(MySocket, DDNSClient.CheckIPServer.szROM); |
||
| 331 | } |
||
| 332 | else |
||
| 333 | { |
||
| 334 | TCPPutString(MySocket, DDNSClient.CheckIPServer.szRAM); |
||
| 335 | } |
||
| 336 | |||
| 337 | TCPPutROMString(MySocket, (ROM BYTE*)"\r\nConnection: close\r\n\r\n"); |
||
| 338 | |||
| 339 | // Send the packet |
||
| 340 | TCPFlush(MySocket); |
||
| 341 | smDDNS++; |
||
| 342 | break; |
||
| 343 | |||
| 344 | case SM_CHECKIP_FIND_DELIMITER: |
||
| 345 | |||
| 346 | // Check if remote node is still connected. If not, force to the disconnect state, |
||
| 347 | // but don't break because data may still be waiting. |
||
| 348 | if(!TCPIsConnected(MySocket) || TickGet() - Timer > 6*TICK_SECOND) |
||
| 349 | smDDNS = SM_CHECKIP_DISCONNECT; |
||
| 350 | |||
| 351 | // Search out the "Address: " delimiter in the response |
||
| 352 | wPos = TCPFindROMArray(MySocket, (ROM BYTE*)"Address: ", 9, 0, FALSE); |
||
| 353 | |||
| 354 | // If not yet found, clear as much as possible and break |
||
| 355 | if(wPos == 0xffff) |
||
| 356 | { |
||
| 357 | wPos = TCPIsGetReady(MySocket); |
||
| 358 | if(wPos > 9u) |
||
| 359 | TCPGetArray(MySocket, NULL, wPos - 9); |
||
| 360 | break; |
||
| 361 | } |
||
| 362 | |||
| 363 | // Clear up to and past that string |
||
| 364 | TCPGetArray(MySocket, NULL, wPos + 9); |
||
| 365 | |||
| 366 | // Continue on to read the IP |
||
| 367 | Timer = TickGet(); |
||
| 368 | smDDNS++; |
||
| 369 | |||
| 370 | case SM_CHECKIP_FIND_ADDRESS: |
||
| 371 | |||
| 372 | // Check if remote node is still connected. If not, force to the disconnect state, |
||
| 373 | // but don't break because data may still be waiting. |
||
| 374 | if(!TCPIsConnected(MySocket) || TickGet() - Timer > 6*TICK_SECOND) |
||
| 375 | smDDNS = SM_CHECKIP_DISCONNECT; |
||
| 376 | |||
| 377 | // Search out the "</body>" delimiter in the response |
||
| 378 | wPos = TCPFindROMArray(MySocket, (ROM BYTE*)"</body>", 7, 0, FALSE); |
||
| 379 | |||
| 380 | // If not yet found, break |
||
| 381 | if(wPos == 0xffff) |
||
| 382 | break; |
||
| 383 | |||
| 384 | // Read and terminate that string as the IP address (preventing buffer overflows) |
||
| 385 | if(wPos > 15u) |
||
| 386 | wPos = 15; |
||
| 387 | TCPGetArray(MySocket, vBuffer, wPos); |
||
| 388 | vBuffer[wPos] = '\0'; |
||
| 389 | |||
| 390 | // Parse the IP address that was read, invalidating on failure |
||
| 391 | if(!StringToIPAddress(vBuffer, &ipParsed)) |
||
| 392 | vBuffer[0] = '\0'; |
||
| 393 | |||
| 394 | // Continue on to close the socket |
||
| 395 | |||
| 396 | case SM_CHECKIP_DISCONNECT: |
||
| 397 | |||
| 398 | // Close the socket |
||
| 399 | TCPDisconnect(MySocket); |
||
| 400 | MySocket = INVALID_SOCKET; |
||
| 401 | |||
| 402 | // Determine if an update is necessary |
||
| 403 | if(vBuffer[0] == '\0') |
||
| 404 | {// CheckIP Failed |
||
| 405 | lastStatus = DDNS_STATUS_CHECKIP_ERROR; |
||
| 406 | smDDNS = SM_SOFT_ERROR; |
||
| 407 | break; |
||
| 408 | } |
||
| 409 | |||
| 410 | if( (ipParsed.Val ==lastKnownIP.Val) && (!bForceUpdate)) |
||
| 411 | { |
||
| 412 | // IP address has not changed and no update is forced |
||
| 413 | lastStatus = DDNS_STATUS_UNCHANGED; |
||
| 414 | smDDNS = SM_DONE; |
||
| 415 | break; |
||
| 416 | } |
||
| 417 | |||
| 418 | // Need to perform an update |
||
| 419 | lastKnownIP = ipParsed; |
||
| 420 | bForceUpdate = FALSE; |
||
| 421 | smDDNS++; |
||
| 422 | break; |
||
| 423 | |||
| 424 | case SM_IP_UPDATE_HOME: |
||
| 425 | |||
| 426 | // Connect a socket to the remote server |
||
| 427 | if(DDNSClient.ROMPointers.UpdateServer) |
||
| 428 | { |
||
| 429 | MySocket = TCPOpen((DWORD)(ROM_PTR_BASE)DDNSClient.UpdateServer.szROM, TCP_OPEN_ROM_HOST, |
||
| 430 | DDNSClient.UpdatePort, TCP_PURPOSE_DEFAULT); |
||
| 431 | } |
||
| 432 | else |
||
| 433 | { |
||
| 434 | MySocket = TCPOpen((DWORD)(PTR_BASE)DDNSClient.UpdateServer.szRAM, TCP_OPEN_RAM_HOST, |
||
| 435 | DDNSClient.UpdatePort, TCP_PURPOSE_DEFAULT); |
||
| 436 | } |
||
| 437 | |||
| 438 | // If no socket is available, try again on the next loop |
||
| 439 | if(MySocket == INVALID_SOCKET) |
||
| 440 | break; |
||
| 441 | |||
| 442 | // Move on to the next state |
||
| 443 | smDDNS++; |
||
| 444 | Timer = TickGet(); |
||
| 445 | break; |
||
| 446 | |||
| 447 | case SM_IP_UPDATE_SKT_OBTAINED: |
||
| 448 | |||
| 449 | // Wait for the remote server to accept our connection request |
||
| 450 | if(!TCPIsConnected(MySocket)) |
||
| 451 | { |
||
| 452 | // Time out if too much time is spent in this state |
||
| 453 | if(TickGet() - Timer > 6*TICK_SECOND) |
||
| 454 | { |
||
| 455 | // Close the socket so it can be used by other modules |
||
| 456 | // We will try again immediately |
||
| 457 | TCPDisconnect(MySocket); |
||
| 458 | MySocket = INVALID_SOCKET; |
||
| 459 | lastStatus = DDNS_STATUS_UPDATE_ERROR; |
||
| 460 | smDDNS--; |
||
| 461 | } |
||
| 462 | break; |
||
| 463 | } |
||
| 464 | |||
| 465 | // Reset timer and begin sending the request |
||
| 466 | Timer = TickGet(); |
||
| 467 | smDDNS++; |
||
| 468 | // No break needed...try to send first bit immediately. |
||
| 469 | |||
| 470 | case SM_IP_UPDATE_REQ_A: |
||
| 471 | |||
| 472 | // Check for lost connections or timeouts |
||
| 473 | if(!TCPIsConnected(MySocket) || (TickGet() - Timer > 10*TICK_SECOND)) |
||
| 474 | { |
||
| 475 | lastStatus = DDNS_STATUS_UPDATE_ERROR; |
||
| 476 | smDDNS = SM_IPUDATE_DISCONNECT; |
||
| 477 | break; |
||
| 478 | } |
||
| 479 | |||
| 480 | if(TCPIsPutReady(MySocket) < 25u) // 25 =~ 16+9 |
||
| 481 | break; |
||
| 482 | |||
| 483 | TCPPutROMString(MySocket, (ROM BYTE*)"GET /nic/update?hostname="); |
||
| 484 | smDDNS++; |
||
| 485 | // No break needed...try to send next bit immediately. |
||
| 486 | |||
| 487 | case SM_IP_UPDATE_REQ_B: |
||
| 488 | |||
| 489 | // Check for lost connections or timeouts |
||
| 490 | if(!TCPIsConnected(MySocket) || (TickGet() - Timer > 10*TICK_SECOND)) |
||
| 491 | { |
||
| 492 | lastStatus = DDNS_STATUS_UPDATE_ERROR; |
||
| 493 | smDDNS = SM_IPUDATE_DISCONNECT; |
||
| 494 | break; |
||
| 495 | } |
||
| 496 | |||
| 497 | // Try to write, verifying that space is available first |
||
| 498 | if(DDNSClient.ROMPointers.Host) |
||
| 499 | { |
||
| 500 | if(TCPIsPutReady(MySocket) < strlenpgm((ROM char*)DDNSClient.Host.szROM)) |
||
| 501 | break; |
||
| 502 | TCPPutROMString(MySocket,DDNSClient.Host.szROM); |
||
| 503 | } |
||
| 504 | else |
||
| 505 | { |
||
| 506 | if(TCPIsPutReady(MySocket) < strlen((char*)DDNSClient.Host.szRAM)) |
||
| 507 | break; |
||
| 508 | TCPPutString(MySocket,DDNSClient.Host.szRAM); |
||
| 509 | } |
||
| 510 | |||
| 511 | smDDNS++; |
||
| 512 | // No break needed...try to send next bit immediately. |
||
| 513 | |||
| 514 | case SM_IP_UPDATE_REQ_C: |
||
| 515 | |||
| 516 | // Check for lost connections or timeouts |
||
| 517 | if(!TCPIsConnected(MySocket) || TickGet() - Timer > 10*TICK_SECOND) |
||
| 518 | { |
||
| 519 | lastStatus = DDNS_STATUS_UPDATE_ERROR; |
||
| 520 | smDDNS = SM_IPUDATE_DISCONNECT; |
||
| 521 | break; |
||
| 522 | } |
||
| 523 | |||
| 524 | if(TCPIsPutReady(MySocket) < 70u) |
||
| 525 | break; |
||
| 526 | |||
| 527 | TCPPutROMString(MySocket, (ROM BYTE*)"&myip="); |
||
| 528 | TCPPutString(MySocket, vBuffer); |
||
| 529 | TCPPutROMString(MySocket, (ROM BYTE*)"&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0"); |
||
| 530 | |||
| 531 | TCPFlush(MySocket); |
||
| 532 | smDDNS++; |
||
| 533 | // No break needed...try to send next bit immediately. |
||
| 534 | |||
| 535 | case SM_IP_UPDATE_REQ_D: |
||
| 536 | |||
| 537 | // Check for lost connections or timeouts |
||
| 538 | if(!TCPIsConnected(MySocket) || TickGet() - Timer > 10*TICK_SECOND) |
||
| 539 | { |
||
| 540 | lastStatus = DDNS_STATUS_UPDATE_ERROR; |
||
| 541 | smDDNS = SM_IPUDATE_DISCONNECT; |
||
| 542 | break; |
||
| 543 | } |
||
| 544 | |||
| 545 | if(TCPIsPutReady(MySocket) < 131u) // 131 =~ 8+23 + dynamic dns server hostname |
||
| 546 | break; |
||
| 547 | |||
| 548 | TCPPutROMString(MySocket, (ROM BYTE*)"\r\nHost: ");//8 |
||
| 549 | |||
| 550 | if(DDNSClient.ROMPointers.UpdateServer) |
||
| 551 | TCPPutROMString(MySocket,DDNSClient.UpdateServer.szROM); |
||
| 552 | else |
||
| 553 | TCPPutString(MySocket,DDNSClient.UpdateServer.szRAM); |
||
| 554 | |||
| 555 | TCPPutROMString(MySocket, (ROM BYTE*)"\r\nAuthorization: Basic ");//23 |
||
| 556 | |||
| 557 | TCPFlush(MySocket); |
||
| 558 | smDDNS++; |
||
| 559 | // No break needed...try to send the next bit immediately. |
||
| 560 | |||
| 561 | case SM_IP_UPDATE_REQ_E: |
||
| 562 | |||
| 563 | // Check for lost connections or timeouts |
||
| 564 | if(!TCPIsConnected(MySocket) || TickGet() - Timer > 6*TICK_SECOND) |
||
| 565 | { |
||
| 566 | lastStatus = DDNS_STATUS_UPDATE_ERROR; |
||
| 567 | smDDNS = SM_IPUDATE_DISCONNECT; |
||
| 568 | break; |
||
| 569 | } |
||
| 570 | |||
| 571 | // User name and passwords for DynDNS.org can each be up to 24 characters |
||
| 572 | // Base64 encoded data is always at least 25% bigger than the original |
||
| 573 | if(TCPIsPutReady(MySocket) < 100u) |
||
| 574 | break; |
||
| 575 | |||
| 576 | if(DDNSClient.ROMPointers.Username) |
||
| 577 | { |
||
| 578 | ROMStrPtr = (ROM char*)DDNSClient.Username.szROM; |
||
| 579 | wPos = strlenpgm(ROMStrPtr); |
||
| 580 | } |
||
| 581 | else |
||
| 582 | { |
||
| 583 | RAMStrPtr = (char*)DDNSClient.Username.szRAM; |
||
| 584 | wPos = strlen((char*)RAMStrPtr); |
||
| 585 | } |
||
| 586 | |||
| 587 | i = 0; |
||
| 588 | while(wPos) |
||
| 589 | { |
||
| 590 | while(i < wPos && i < 3u) |
||
| 591 | { |
||
| 592 | if(DDNSClient.ROMPointers.Username) |
||
| 593 | vBuffer[i] = *ROMStrPtr++; |
||
| 594 | else |
||
| 595 | vBuffer[i] = *RAMStrPtr++; |
||
| 596 | i++; |
||
| 597 | } |
||
| 598 | wPos -= i; |
||
| 599 | |||
| 600 | if(i == 3u) |
||
| 601 | { |
||
| 602 | Base64Encode(vBuffer, i, vBuffer, 4); |
||
| 603 | TCPPutArray(MySocket, vBuffer, 4); |
||
| 604 | i = 0; |
||
| 605 | } |
||
| 606 | } |
||
| 607 | |||
| 608 | if(DDNSClient.ROMPointers.Password) |
||
| 609 | { |
||
| 610 | ROMStrPtr = (ROM char*)DDNSClient.Password.szROM; |
||
| 611 | wPos = strlenpgm(ROMStrPtr); |
||
| 612 | } |
||
| 613 | else |
||
| 614 | { |
||
| 615 | RAMStrPtr = (char*)DDNSClient.Password.szRAM; |
||
| 616 | wPos = strlen((char*)RAMStrPtr); |
||
| 617 | } |
||
| 618 | |||
| 619 | // Increment for the ':' separator and i for bytes left in username |
||
| 620 | wPos += i + 1; |
||
| 621 | |||
| 622 | vBuffer[i++] = ':'; |
||
| 623 | |||
| 624 | while(wPos) |
||
| 625 | { |
||
| 626 | while(i < wPos && i < 3u) |
||
| 627 | { |
||
| 628 | if(DDNSClient.ROMPointers.Password) |
||
| 629 | vBuffer[i] = *ROMStrPtr++; |
||
| 630 | else |
||
| 631 | vBuffer[i] = *RAMStrPtr++; |
||
| 632 | i++; |
||
| 633 | } |
||
| 634 | wPos -= i; |
||
| 635 | Base64Encode(vBuffer, i, vBuffer, 4); |
||
| 636 | TCPPutArray(MySocket, vBuffer, 4); |
||
| 637 | i = 0; |
||
| 638 | } |
||
| 639 | |||
| 640 | TCPFlush(MySocket); |
||
| 641 | smDDNS++; |
||
| 642 | break; |
||
| 643 | |||
| 644 | |||
| 645 | case SM_IP_UPDATE_REQ_F: |
||
| 646 | |||
| 647 | // Check for lost connections or timeouts |
||
| 648 | if(!TCPIsConnected(MySocket) || TickGet() - Timer > 10*TICK_SECOND) |
||
| 649 | { |
||
| 650 | lastStatus = DDNS_STATUS_UPDATE_ERROR; |
||
| 651 | smDDNS = SM_IPUDATE_DISCONNECT; |
||
| 652 | break; |
||
| 653 | } |
||
| 654 | |||
| 655 | if(TCPIsPutReady(MySocket) < 50u) |
||
| 656 | break; |
||
| 657 | |||
| 658 | TCPPutROMString(MySocket, (ROM BYTE*)"\r\nUser-Agent: Microchip - TCPIPSTACK - "TCPIP_STACK_VERSION"\r\n\r\n"); |
||
| 659 | TCPFlush(MySocket); |
||
| 660 | smDDNS++; |
||
| 661 | |||
| 662 | // Reset the timer to wait for a response |
||
| 663 | Timer = TickGet(); |
||
| 664 | break; |
||
| 665 | |||
| 666 | case SM_IPUPDATE_FIND_RESPONSE: |
||
| 667 | // Locate the response string |
||
| 668 | |||
| 669 | // Wait up to 10 seconds for a response |
||
| 670 | if(TickGet() - Timer > 10*TICK_SECOND) |
||
| 671 | { |
||
| 672 | lastStatus = DDNS_STATUS_UPDATE_ERROR; |
||
| 673 | smDDNS = SM_IPUDATE_DISCONNECT; |
||
| 674 | break; |
||
| 675 | } |
||
| 676 | |||
| 677 | // According to HTTP, the response will start after the two CRLFs |
||
| 678 | wPos = TCPFindROMArray(MySocket, (ROM BYTE*)"\r\n\r\n", 4, 0, FALSE); |
||
| 679 | |||
| 680 | // If not yet found, eliminate everything up to |
||
| 681 | if(wPos == 0xffff) |
||
| 682 | { |
||
| 683 | wPos = TCPIsGetReady(MySocket); |
||
| 684 | if(wPos > 4u) |
||
| 685 | TCPGetArray(MySocket, NULL, wPos - 4); |
||
| 686 | break; |
||
| 687 | } |
||
| 688 | |||
| 689 | TCPGetArray(MySocket, NULL, wPos+4); |
||
| 690 | smDDNS++; |
||
| 691 | // No break...continue to next state immediately |
||
| 692 | |||
| 693 | case SM_IPUPDATE_PARSE_RESPONSE: |
||
| 694 | // Try to parse the response text |
||
| 695 | |||
| 696 | // Wait up to 10 seconds for the remote server to disconnect |
||
| 697 | // so we know all data has been received |
||
| 698 | if(TCPIsConnected(MySocket) && TickGet() - Timer < 10*TICK_SECOND) |
||
| 699 | break; |
||
| 700 | |||
| 701 | // Read the response code |
||
| 702 | wPos = TCPIsGetReady(MySocket); |
||
| 703 | if(wPos > sizeof(vBuffer) - 1) |
||
| 704 | wPos = sizeof(vBuffer) - 1; |
||
| 705 | |||
| 706 | wPos = TCPGetArray(MySocket, vBuffer, wPos); |
||
| 707 | vBuffer[wPos] = '\0'; |
||
| 708 | for(i = 0; i < sizeof(vBuffer); i++) |
||
| 709 | if(vBuffer[i] == ' ') |
||
| 710 | vBuffer[i] = '\0'; |
||
| 711 | |||
| 712 | for(lastStatus = 0; lastStatus <= DDNS_STATUS_UPDATE_ERROR; lastStatus++) |
||
| 713 | if(!strcmppgm2ram((char*)vBuffer, (ROM char*)_updateIpSrvrResponse[lastStatus])) |
||
| 714 | break; |
||
| 715 | |||
| 716 | smDDNS++; |
||
| 717 | // No break...continue to finalization |
||
| 718 | |||
| 719 | case SM_IPUDATE_DISCONNECT: |
||
| 720 | // Close the socket so it can be used by other modules. |
||
| 721 | if(MySocket != INVALID_SOCKET) |
||
| 722 | { |
||
| 723 | TCPDisconnect(MySocket); |
||
| 724 | MySocket = INVALID_SOCKET; |
||
| 725 | } |
||
| 726 | |||
| 727 | // Determine what to do based on status |
||
| 728 | if(lastStatus <= DDNS_STATUS_NUMHOST || lastStatus == DDNS_STATUS_UNCHANGED) |
||
| 729 | smDDNS = SM_DONE; |
||
| 730 | else if(lastStatus == DDNS_STATUS_911 || lastStatus == DDNS_STATUS_DNSERR) |
||
| 731 | smDDNS = SM_SYSTEM_ERROR; |
||
| 732 | else |
||
| 733 | smDDNS = SM_SOFT_ERROR; |
||
| 734 | |||
| 735 | smDDNS++; |
||
| 736 | break; |
||
| 737 | |||
| 738 | case SM_DONE: |
||
| 739 | dwUpdateAt = TickGet() + 10*60*TICK_SECOND; // 10 minutes |
||
| 740 | smDDNS = SM_IDLE; |
||
| 741 | break; |
||
| 742 | |||
| 743 | case SM_SOFT_ERROR: |
||
| 744 | dwUpdateAt = TickGet() + 30*TICK_SECOND; // 30 seconds |
||
| 745 | smDDNS = SM_IDLE; |
||
| 746 | break; |
||
| 747 | |||
| 748 | case SM_SYSTEM_ERROR: |
||
| 749 | dwUpdateAt = TickGet() + 30*60*TICK_SECOND; // 30 minutes |
||
| 750 | smDDNS = SM_IDLE; |
||
| 751 | break; |
||
| 752 | } |
||
| 753 | } |
||
| 754 | |||
| 755 | /***************************************************************************** |
||
| 756 | Function: |
||
| 757 | void DDNSForceUpdate(void) |
||
| 758 | |||
| 759 | Summary: |
||
| 760 | Forces an immediate DDNS update |
||
| 761 | |||
| 762 | Description: |
||
| 763 | This function forces the DDNS Client to execute a full update |
||
| 764 | immediately. Any error message is cleared, and the update will be |
||
| 765 | executed whether the IP address has changed or not. Call this |
||
| 766 | function every time the DDNSClient parameters have been modified. |
||
| 767 | |||
| 768 | Precondition: |
||
| 769 | DDNSInit must have been called. |
||
| 770 | |||
| 771 | Parameters: |
||
| 772 | None |
||
| 773 | |||
| 774 | Returns: |
||
| 775 | None |
||
| 776 | ***************************************************************************/ |
||
| 777 | void DDNSForceUpdate(void) |
||
| 778 | { |
||
| 779 | // Force update on next DDNSClient call |
||
| 780 | dwUpdateAt = TickGet(); |
||
| 781 | bForceUpdate = TRUE; |
||
| 782 | lastStatus = DDNS_STATUS_UNKNOWN; |
||
| 783 | } |
||
| 784 | |||
| 785 | /***************************************************************************** |
||
| 786 | Function: |
||
| 787 | void DDNSSetService(DDNS_SERVICES svc) |
||
| 788 | |||
| 789 | Summary: |
||
| 790 | Selects a pre-configured Dynamic DNS service |
||
| 791 | |||
| 792 | Description: |
||
| 793 | This function selects a Dynamic DNS service based on parameters |
||
| 794 | configured in ddnsServiceHosts and ddnsServicePorts. These arrays |
||
| 795 | must match the DDNS_SERVICES enumeration. |
||
| 796 | |||
| 797 | Precondition: |
||
| 798 | None |
||
| 799 | |||
| 800 | Parameters: |
||
| 801 | svc - one of the DDNS_SERVICES elements to indicate the selected service |
||
| 802 | |||
| 803 | Returns: |
||
| 804 | None |
||
| 805 | ***************************************************************************/ |
||
| 806 | void DDNSSetService(DDNS_SERVICES svc) |
||
| 807 | { |
||
| 808 | DDNSClient.ROMPointers.UpdateServer = 1; |
||
| 809 | DDNSClient.UpdateServer.szROM = (ROM BYTE*)ddnsServiceHosts[svc]; |
||
| 810 | DDNSClient.UpdatePort = ddnsServicePorts[svc]; |
||
| 811 | } |
||
| 812 | |||
| 813 | |||
| 814 | /***************************************************************************** |
||
| 815 | Function: |
||
| 816 | IP_ADDR DDNSGetLastIP(void) |
||
| 817 | |||
| 818 | Summary: |
||
| 819 | Returns the last known external IP address of the device. |
||
| 820 | |||
| 821 | Description: |
||
| 822 | This function returns the last known external IP address of the device. |
||
| 823 | |||
| 824 | Precondition: |
||
| 825 | None |
||
| 826 | |||
| 827 | Parameters: |
||
| 828 | None |
||
| 829 | |||
| 830 | Returns: |
||
| 831 | The last known external IP address of the device. |
||
| 832 | ***************************************************************************/ |
||
| 833 | IP_ADDR DDNSGetLastIP(void) |
||
| 834 | { |
||
| 835 | return lastKnownIP; |
||
| 836 | } |
||
| 837 | |||
| 838 | |||
| 839 | |||
| 840 | /***************************************************************************** |
||
| 841 | Function: |
||
| 842 | DDNS_STATUS DDNSGetLastStatus(void) |
||
| 843 | |||
| 844 | Summary: |
||
| 845 | Returns the status of the most recent update. |
||
| 846 | |||
| 847 | Description: |
||
| 848 | This function returns the status of the most recent update. See the |
||
| 849 | DDNS_STATUS enumeration for possible codes. |
||
| 850 | |||
| 851 | Precondition: |
||
| 852 | None |
||
| 853 | |||
| 854 | Parameters: |
||
| 855 | None |
||
| 856 | |||
| 857 | Returns: |
||
| 858 | DDNS_STATUS indicating the status code for the most recent update. |
||
| 859 | ***************************************************************************/ |
||
| 860 | |||
| 861 | DDNS_STATUS DDNSGetLastStatus(void) |
||
| 862 | { |
||
| 863 | return lastStatus; |
||
| 864 | } |
||
| 865 | |||
| 866 | #endif //STACK_USE_DYNAMICDNS_CLIENT |
||
| 867 | #endif //__DYNDNSCLIENT_C |
||
| 868 |
Powered by WebSVN v2.8.3