]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/ankh/examples/pingpong/ping.cc
update
[l4.git] / l4 / pkg / ankh / examples / pingpong / ping.cc
1 #include <l4/re/env>
2 #include <l4/re/namespace>
3 #include <l4/re/util/cap_alloc>
4 #include <l4/cxx/ipc_stream>
5 #include <l4/ankh/protocol>
6 #include <l4/ankh/shm>
7 #include <l4/ankh/session>
8 #include <l4/util/util.h>
9 #include <l4/shmc/shmc.h>
10 #include <boost/format.hpp>
11 #include <iostream>
12 #include <cstring>
13 #include <l4/sys/debugger.h>
14 #include <pthread-l4.h>
15 #include <cstdlib>
16
17 Ankh::Shm_receiver *recv;
18 Ankh::Shm_sender   *send;
19 Ankh::Shm_chunk    *info;
20 char *shm_name;
21
22 int cfg_shmsize = 2048;
23 l4shmc_area_t ankh_shmarea;
24
25 #define mac_fmt       "%02X:%02X:%02X:%02X:%02X:%02X"
26 #define mac_str(mac)  (unsigned char)((mac)[0]), (unsigned char)((mac)[1]), \
27                       (unsigned char)((mac)[2]), (unsigned char)((mac)[3]), \
28                       (unsigned char)((mac)[4]), (unsigned char)((mac)[5])
29
30 static const int print_rate = 30000;
31 unsigned char const bcast_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
32
33 /*
34  * Print a MAC formatted
35  */
36 static void print_mac(unsigned char *macptr)
37 {
38         char macbuf_size = 32;
39         char mac_buf[macbuf_size];
40         snprintf(mac_buf, macbuf_size, mac_fmt, mac_str(macptr));
41         boost::format f("%1$-18s");
42         f % &mac_buf[0];
43         std::cout << f;
44 }
45
46
47 static char *human_readable_size(unsigned size) {
48         char sizebuf[40];
49
50         if (size < 1000)
51                 snprintf(sizebuf, sizeof(sizebuf), "%d B", size);
52         else if (size < 1000000)
53                 snprintf(sizebuf, sizeof(sizebuf), "%.02f kiB", size/1000.0);
54         else if (size < 1000000000)
55                 snprintf(sizebuf, sizeof(sizebuf), "%.02f MiB", size/1000000.0);
56         else
57                 snprintf(sizebuf, sizeof(sizebuf), "%.02f GiB", size/1000000000.0);
58
59         return strdup(sizebuf);
60 }
61
62
63 /*
64  * Print my device's stats
65  */
66 static void print_stats()
67 {
68         struct AnkhSessionDescriptor *sd = reinterpret_cast<struct AnkhSessionDescriptor*>(info->addr());
69
70         std::cout << "info @ " << (void*)sd << "\n";
71         print_mac(&sd->mac[0]); std::cout << "MTU " << sd->mtu << "\n";
72         std::cout << "RX packets: " << sd->num_rx << " dropped: "    << sd->rx_dropped << "\n";
73         std::cout << "TX packets: " << sd->num_tx << " dropped: "    << sd->tx_dropped << "\n";
74         char *s1 = human_readable_size(sd->rx_bytes);
75         char *s2 = human_readable_size(sd->tx_bytes);
76         std::cout << "RX bytes: "  << s1 
77                   << " TX bytes: " << s2 << "\n";
78         free(s1); free(s2);
79 }
80
81 static void ankh_activate()
82 {
83         L4::Cap<void> ankh_server;
84
85         if (!(ankh_server = L4Re::Env::env()->get_cap<void>("ankh"))) {
86                 printf("Could not find Ankh server.\n");
87                 assert(false);
88         }
89
90         L4::Ipc::Iostream s(l4_utcb());
91
92         s << l4_umword_t(Ankh::Opcode::Activate);
93
94         l4_msgtag_t res = s.call(ankh_server.cap(), Ankh::Protocol::Ankh);
95         ASSERT_EQUAL(l4_ipc_error(res, l4_utcb()), 0);
96
97         printf("activated Ankh connection.\n");
98 }
99
100
101 static void get_shm_area(L4::Cap<void> /*session*/)
102 {
103         int err = l4shmc_attach(shm_name, &ankh_shmarea);
104         ASSERT_OK(err);
105         std::cout << "Attached shm area '" << shm_name << "': " << err << "\n";
106
107         Ankh::Shm_ringbuffer *send_rb = Ankh::Shm_ringbuffer::create(
108                                            &ankh_shmarea, "tx_ring",
109                                            "tx_signal", cfg_shmsize);
110         Ankh::Shm_ringbuffer *recv_rb = Ankh::Shm_ringbuffer::create(
111                                            &ankh_shmarea, "rx_ring",
112                                            "rx_signal", cfg_shmsize);
113         Ankh::Shm_chunk *info_chunk   = Ankh::Shm_chunk::create(&ankh_shmarea,
114                                            "info", sizeof(AnkhSessionDescriptor));
115
116         std::cout << "SEND RB @ " << (void*)send_rb
117                   << " RECV RB @ " << (void*)recv_rb
118                   << " INFO @ " << (void *)info_chunk << "\n";
119
120         ankh_activate();
121
122         send = new Ankh::Shm_sender(&ankh_shmarea, "tx_ring",
123                                     "tx_signal");
124         std::cout << "sender: " << (void*)send << "\n";
125         recv = new Ankh::Shm_receiver(&ankh_shmarea, "rx_ring",
126                                       "rx_signal");
127         std::cout << "receiver: " << (void*)recv << "\n";
128
129         info = Ankh::Shm_chunk::get(&ankh_shmarea, "info",
130                                     sizeof(struct AnkhSessionDescriptor));
131
132         struct AnkhSessionDescriptor *sd = reinterpret_cast<struct AnkhSessionDescriptor*>(info->addr());
133
134         std::cout << "Got assigned MAC: ";
135         print_mac(sd->mac);
136         std::cout << "\n";
137         print_stats();
138 }
139
140
141 #if 0
142 #define DEBUG(x) \
143         std::cout << x;
144 #else
145 #define DEBUG(x) {}
146 #endif
147
148 typedef struct {
149         unsigned char _1[4];
150         unsigned char txbuf[1024];
151         unsigned char _2[4];
152         unsigned char rxbuf[1024];
153         unsigned char _3[4];
154         const unsigned char packet_const;
155         unsigned char _4[4];
156 } rx_struct;
157
158 rx_struct recv_buffer = {
159         {0xAA, 0xAA, 0xAA, 0xAA},
160         {0, },
161         {0xBB, 0xBB, 0xBB, 0xBB},
162         {0, },
163         {0xCC, 0xCC, 0xCC, 0xCC},
164         0x1B,
165         {0xDD, 0xDD, 0xDD, 0xDD}
166 };
167
168
169 static void
170 generate_packet(unsigned char *buf,
171                                 unsigned char dest[6],
172                                 unsigned char src[6],
173                                 unsigned char payload,
174                                 unsigned size)
175 {
176         memcpy(buf, dest, 6);
177         memcpy(buf+6, src, 6);
178         memset(buf+12, payload, size);
179 }
180
181 static void send_packet(Ankh::Shm_sender *snd,
182                                                 unsigned char *packet,
183                                                 unsigned size)
184 {
185         DEBUG("sending()\n");
186         int err = snd->next_copy_in((char*)packet, size);
187         assert(err == 0);
188         DEBUG("commit()\n");
189         snd->commit_packet();
190 }
191
192 static void recv_packet(Ankh::Shm_receiver *rcv,
193                                                 unsigned char *buf,
194                                                 unsigned *size)
195 {
196         DEBUG("recv()\n");
197         recv->wait_for_data();
198         DEBUG("got data.\n");
199         int err = rcv->next_copy_out((char*)buf, size);
200         assert(err == 0);
201         DEBUG("copied out\n");
202 }
203
204
205 static void sanity_check_packet(unsigned char *buf,
206                                                  unsigned char src[6],
207                                                  unsigned char dest[6],
208                                                  unsigned char payload,
209                                                  unsigned size)
210 {
211         if (memcmp(buf, dest, 6)) {
212                 std::cout << "Dest mismatch in buf @ " << (void*)buf << " ";
213                 print_mac(buf);
214                 std::cout << " <-> ";
215                 print_mac(dest);
216                 std::cout << std::endl;
217                 assert(memcmp(buf, dest, 6) == 0);
218         }
219         if (memcmp(buf + 6, src, 6)) {
220                 std::cout << "Src mismatch in buf @ " << (void*)buf << " ";
221                 print_mac(buf+6);
222                 std::cout << " <-> ";
223                 print_mac(src);
224                 std::cout << std::endl;
225                 assert(memcmp(buf+6, src, 6) == 0);
226         }
227
228         unsigned char *c = buf + 12;
229         for ( ; c < buf + size; ++c)
230                 assert(*c == payload);
231 }
232
233 static void morping()
234 {
235         unsigned char mac[6]       = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
236         unsigned char mymac[6]     = {0x00};
237         unsigned bufsize = sizeof(recv_buffer.txbuf);
238         // minimum size for sending test packets
239         int min_size = 20;
240         // maximum random element in size: bufsize - header len - minimum size
241         int data_size = bufsize - 12 - min_size; 
242         unsigned size;
243
244         memcpy(mymac, reinterpret_cast<struct AnkhSessionDescriptor*>(info->addr())->mac, 6);
245
246         l4_sleep(100);
247         printf("MY MAC: "); print_mac(mymac); printf("\n");
248         for (int cnt = 0; ; cnt++)
249         {
250                 /*
251                  * random data size:
252                  * minimum_size <= rand <= data_size
253                  */
254                 int rand = random() % data_size + min_size;
255
256                 generate_packet(recv_buffer.txbuf, mac, mymac, recv_buffer.packet_const, rand);
257
258                 size = rand + 12; // data + sizeof(header)
259                 send_packet(send, &recv_buffer.txbuf[0], size);
260
261                 size = bufsize;
262                 recv_packet(recv, &recv_buffer.rxbuf[0], &size);
263
264                 /*
265                  * This task will always receive second. This means,
266                  * the packet will contain valid MACs, but our own
267                  * representation of the partner's MAC will be bcast.
268                  * Therefore, we extract the partner's MAC from the
269                  * packet's sender field.
270                  */
271                 if (memcmp(mac, bcast_mac, 6) == 0)
272                         memcpy(mac, recv_buffer.rxbuf + 6, 6);
273                 else
274                         sanity_check_packet(recv_buffer.rxbuf, mac, mymac, recv_buffer.packet_const, rand);
275
276                 if (cnt > print_rate) {
277                         print_stats();
278                         cnt = 0;
279                 }
280         }
281 }
282
283 static void morpong()
284 {
285         unsigned char mac[6]       = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
286         unsigned char mymac[6]     = {0x00};
287         unsigned bufsize = sizeof(recv_buffer.txbuf);
288         unsigned size;
289
290         memcpy(mymac, reinterpret_cast<struct AnkhSessionDescriptor*>(info->addr())->mac, 6);
291
292         printf("MY MAC: "); print_mac(mymac); printf("\n");
293         for (int cnt = 0; ; cnt++)
294         {
295                 size = bufsize;
296                 recv_packet(recv, &recv_buffer.rxbuf[0], &size);
297
298                 /*
299                  * This task will always recv() first, so the recipient
300                  * MAC of the first packet will be a bcast one. If we
301                  * find this, we extract the partner's MAC from the sender
302                  * field.
303                  */
304                 if (memcmp(recv_buffer.rxbuf, bcast_mac, 6) == 0)
305                         memcpy(mac, recv_buffer.rxbuf + 6, 6);
306                 else
307                         sanity_check_packet(recv_buffer.rxbuf, mac, mymac, recv_buffer.packet_const, size);
308
309                 generate_packet(recv_buffer.txbuf, mac, mymac, recv_buffer.packet_const, size-12);
310
311                 send_packet(send, &recv_buffer.txbuf[0], size);
312
313                 if (cnt > print_rate+1) {
314                         print_stats();
315                         cnt = 0;
316                 }
317         }
318 }
319
320
321 static void setup_debug_names(std::string const &name)
322 {
323         std::cout << "I am " << name << "\n";
324
325         std::cout << "My TID = 0x" << std::hex << l4_debugger_global_id(pthread_getl4cap(pthread_self()))
326                   << std::dec << "\n";
327         //std::cout << "Ready to contact Ankh.\n";
328         char const *c = name.c_str();
329         for ( ; *c++ != '/'; ) ;
330
331         std::cout << c << "\n";
332         l4_debugger_set_object_name(pthread_getl4cap(pthread_self()), c);
333
334 }
335
336
337 int main(int argc, char **argv)
338 {
339         if (argc > 1) {
340                 std::cout << "Using shm area: '" << argv[1] << "'\n";
341                 shm_name = strdup(argv[1]);
342         }
343
344         L4::Cap<void> ankh_session;
345         if (!(ankh_session = L4Re::Env::env()->get_cap<void>("ankh")))
346         {
347                 std::cout << "Ankh not found.\n";
348                 return 1;
349         }
350
351         get_shm_area(ankh_session);
352
353         std::string name(argv[0]);
354         std::cout << name << "\n";
355         setup_debug_names(name);
356         std::cout << "txbuf @ " << (void*)recv_buffer.txbuf << ", rxbuf @ " << (void*)recv_buffer.rxbuf << std::endl;
357
358         if (name == "rom/morping")
359                 morping();
360         else
361                 morpong();
362
363         l4_sleep_forever();
364         return 0;
365 }