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