/[lwip]/contrib/apps/ping/ping.c
ViewVC logotype

Contents of /contrib/apps/ping/ping.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.28 - (show annotations) (download)
Sun May 16 16:07:11 2010 UTC (13 years, 6 months ago) by goldsimon
Branch: MAIN
CVS Tags: STABLE-1_4_0, cvs-repository-moved-to-git, STABLE-1_4_0-RC2, STABLE-1_4_0-RC1, HEAD
Changes since 1.27: +1 -0 lines
File MIME type: text/plain
Fix a compiler warning

1 /**
2 * @file
3 * Ping sender module
4 *
5 */
6
7 /*
8 * Redistribution and use in source and binary forms, with or without modification,
9 * are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
28 * OF SUCH DAMAGE.
29 *
30 * This file is part of the lwIP TCP/IP stack.
31 *
32 */
33
34 /**
35 * This is an example of a "ping" sender (with raw API and socket API).
36 * It can be used as a start point to maintain opened a network connection, or
37 * like a network "watchdog" for your device.
38 *
39 */
40
41 #include "lwip/opt.h"
42
43 #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
44
45 #include "ping.h"
46
47 #include "lwip/mem.h"
48 #include "lwip/raw.h"
49 #include "lwip/icmp.h"
50 #include "lwip/netif.h"
51 #include "lwip/sys.h"
52 #include "lwip/timers.h"
53 #include "lwip/inet_chksum.h"
54
55 #if PING_USE_SOCKETS
56 #include "lwip/sockets.h"
57 #include "lwip/inet.h"
58 #endif /* PING_USE_SOCKETS */
59
60
61 /**
62 * PING_DEBUG: Enable debugging for PING.
63 */
64 #ifndef PING_DEBUG
65 #define PING_DEBUG LWIP_DBG_ON
66 #endif
67
68 /** ping target - should be a "ip_addr_t" */
69 #ifndef PING_TARGET
70 #define PING_TARGET (netif_default?netif_default->gw:ip_addr_any)
71 #endif
72
73 /** ping receive timeout - in milliseconds */
74 #ifndef PING_RCV_TIMEO
75 #define PING_RCV_TIMEO 1000
76 #endif
77
78 /** ping delay - in milliseconds */
79 #ifndef PING_DELAY
80 #define PING_DELAY 1000
81 #endif
82
83 /** ping identifier - must fit on a u16_t */
84 #ifndef PING_ID
85 #define PING_ID 0xAFAF
86 #endif
87
88 /** ping additional data size to include in the packet */
89 #ifndef PING_DATA_SIZE
90 #define PING_DATA_SIZE 32
91 #endif
92
93 /** ping result action - no default action */
94 #ifndef PING_RESULT
95 #define PING_RESULT(ping_ok)
96 #endif
97
98 /* ping variables */
99 static u16_t ping_seq_num;
100 static u32_t ping_time;
101 #if !PING_USE_SOCKETS
102 static struct raw_pcb *ping_pcb;
103 #endif /* PING_USE_SOCKETS */
104
105 /** Prepare a echo ICMP request */
106 static void
107 ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
108 {
109 size_t i;
110 size_t data_len = len - sizeof(struct icmp_echo_hdr);
111
112 ICMPH_TYPE_SET(iecho, ICMP_ECHO);
113 ICMPH_CODE_SET(iecho, 0);
114 iecho->chksum = 0;
115 iecho->id = PING_ID;
116 iecho->seqno = htons(++ping_seq_num);
117
118 /* fill the additional data buffer with some data */
119 for(i = 0; i < data_len; i++) {
120 ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
121 }
122
123 iecho->chksum = inet_chksum(iecho, len);
124 }
125
126 #if PING_USE_SOCKETS
127
128 /* Ping using the socket ip */
129 static err_t
130 ping_send(int s, ip_addr_t *addr)
131 {
132 int err;
133 struct icmp_echo_hdr *iecho;
134 struct sockaddr_in to;
135 size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
136 LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff);
137
138 iecho = (struct icmp_echo_hdr *)mem_malloc((mem_size_t)ping_size);
139 if (!iecho) {
140 return ERR_MEM;
141 }
142
143 ping_prepare_echo(iecho, (u16_t)ping_size);
144
145 to.sin_len = sizeof(to);
146 to.sin_family = AF_INET;
147 inet_addr_from_ipaddr(&to.sin_addr, addr);
148
149 err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to));
150
151 mem_free(iecho);
152
153 return (err ? ERR_OK : ERR_VAL);
154 }
155
156 static void
157 ping_recv(int s)
158 {
159 char buf[64];
160 int fromlen, len;
161 struct sockaddr_in from;
162 struct ip_hdr *iphdr;
163 struct icmp_echo_hdr *iecho;
164
165 while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) {
166 if (len >= (int)(sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) {
167 ip_addr_t fromaddr;
168 inet_addr_to_ipaddr(&fromaddr, &from.sin_addr);
169 LWIP_DEBUGF( PING_DEBUG, ("ping: recv "));
170 ip_addr_debug_print(PING_DEBUG, &fromaddr);
171 LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now() - ping_time)));
172
173 iphdr = (struct ip_hdr *)buf;
174 iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4));
175 if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) {
176 /* do some ping result processing */
177 PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER));
178 return;
179 } else {
180 LWIP_DEBUGF( PING_DEBUG, ("ping: drop\n"));
181 }
182 }
183 }
184
185 if (len == 0) {
186 LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %"U32_F" ms - timeout\n", (sys_now()-ping_time)));
187 }
188
189 /* do some ping result processing */
190 PING_RESULT(0);
191 }
192
193 static void
194 ping_thread(void *arg)
195 {
196 int s;
197 int timeout = PING_RCV_TIMEO;
198 ip_addr_t ping_target;
199
200 LWIP_UNUSED_ARG(arg);
201
202 if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) {
203 return;
204 }
205
206 lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
207
208 while (1) {
209 ping_target = PING_TARGET;
210
211 if (ping_send(s, &ping_target) == ERR_OK) {
212 LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
213 ip_addr_debug_print(PING_DEBUG, &ping_target);
214 LWIP_DEBUGF( PING_DEBUG, ("\n"));
215
216 ping_time = sys_now();
217 ping_recv(s);
218 } else {
219 LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
220 ip_addr_debug_print(PING_DEBUG, &ping_target);
221 LWIP_DEBUGF( PING_DEBUG, (" - error\n"));
222 }
223 sys_msleep(PING_DELAY);
224 }
225 }
226
227 #else /* PING_USE_SOCKETS */
228
229 /* Ping using the raw ip */
230 static u8_t
231 ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)
232 {
233 struct icmp_echo_hdr *iecho;
234 LWIP_UNUSED_ARG(arg);
235 LWIP_UNUSED_ARG(pcb);
236 LWIP_UNUSED_ARG(addr);
237 LWIP_ASSERT("p != NULL", p != NULL);
238
239 if (pbuf_header( p, -PBUF_IP_HLEN)==0) {
240 iecho = (struct icmp_echo_hdr *)p->payload;
241
242 if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) {
243 LWIP_DEBUGF( PING_DEBUG, ("ping: recv "));
244 ip_addr_debug_print(PING_DEBUG, addr);
245 LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time)));
246
247 /* do some ping result processing */
248 PING_RESULT(1);
249 pbuf_free(p);
250 return 1; /* eat the packet */
251 }
252 }
253
254 return 0; /* don't eat the packet */
255 }
256
257 static void
258 ping_send(struct raw_pcb *raw, ip_addr_t *addr)
259 {
260 struct pbuf *p;
261 struct icmp_echo_hdr *iecho;
262 size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;
263
264 LWIP_DEBUGF( PING_DEBUG, ("ping: send "));
265 ip_addr_debug_print(PING_DEBUG, addr);
266 LWIP_DEBUGF( PING_DEBUG, ("\n"));
267 LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff);
268
269 p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM);
270 if (!p) {
271 return;
272 }
273 if ((p->len == p->tot_len) && (p->next == NULL)) {
274 iecho = (struct icmp_echo_hdr *)p->payload;
275
276 ping_prepare_echo(iecho, (u16_t)ping_size);
277
278 raw_sendto(raw, p, addr);
279 ping_time = sys_now();
280 }
281 pbuf_free(p);
282 }
283
284 static void
285 ping_timeout(void *arg)
286 {
287 struct raw_pcb *pcb = (struct raw_pcb*)arg;
288 ip_addr_t ping_target = PING_TARGET;
289
290 LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL);
291
292 ping_send(pcb, &ping_target);
293
294 sys_timeout(PING_DELAY, ping_timeout, pcb);
295 }
296
297 static void
298 ping_raw_init(void)
299 {
300 ping_pcb = raw_new(IP_PROTO_ICMP);
301 LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL);
302
303 raw_recv(ping_pcb, ping_recv, NULL);
304 raw_bind(ping_pcb, IP_ADDR_ANY);
305 sys_timeout(PING_DELAY, ping_timeout, ping_pcb);
306 }
307
308 void
309 ping_send_now()
310 {
311 ip_addr_t ping_target = PING_TARGET;
312 LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL);
313 ping_send(ping_pcb, &ping_target);
314 }
315
316 #endif /* PING_USE_SOCKETS */
317
318 void
319 ping_init(void)
320 {
321 #if PING_USE_SOCKETS
322 sys_thread_new("ping_thread", ping_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
323 #else /* PING_USE_SOCKETS */
324 ping_raw_init();
325 #endif /* PING_USE_SOCKETS */
326 }
327
328 #endif /* LWIP_RAW */

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26